To have conditional ANDing inside WHERE clause - sybase

Can we add null check over one of the parameter of procedure inside WHERE clause and avoid block of code getting repeated like
select aa=t1.aa,bb=t2.bb ,cc=t3.cc
from t1,t2,t3,t4,t5
where t1.p1=t2.p1
and t2.p2=t3.p2
IF(procParameter IS NOT NULL)
and t3.p2=procParameter
and t4.p2=t5.p2
and t5.p3=t1.p2
Look I want one of the AND to get executed conditionally and otherwise it should NOT GET EXECUTED AT ALL..!!!!
How should I go for this optimisation??
I dont want code repeatation like
IF(procParameter IS NOT NULL)
begin
select aa=t1.aa,bb=t2.bb ,cc=t3.cc
from t1,t2,t3,t4,t5
where t1.p1=t2.p1
and t2.p2=t3.p2
and t3.p2=procParameter
and t4.p2=t5.p2
and t5.p3=t1.p2
end
Else
begin
select aa=t1.aa,bb=t2.bb ,cc=t3.cc
from t1,t2,t3,t4,t5
where t1.p1=t2.p1
and t2.p2=t3.p2
and t4.p2=t5.p2
and t5.p3=t1.p2
end
Thanks,

This is one approach:
AND (procParameter IS NULL OR t3.p2=procParameter)

Related

how to use a sql substring in a where in string list conditional

I have a where conditional
where
pnumber in ('mem1234', 'mem2345','mem8978')
I need a substring without the mem in this where conditional. There are a couple hundred strings in this where conditional.
What is the syntax for this?
In order to manipulate the data you will first need to insert it into a temp table/ table variable and then depending on how consistant your data is you could try the following:
DECLARE #pNumbers TABLE (item varchar(20))
insert into #pNumbers values('mem1234'),('mem2345'),('mem8978')
select
REPLACE(item, 'mem', '') AS ReplaceMethod ,
SUBSTRING(item, 4, 4) AS SubstringMethod,
RIGHT(item,LEN(item) - 3) AS Right_LenMethod
FROM #pNumbers
You would then add one of them methods to a subquery in the WHERE
WHERE
pnumber IN ( SELECT REPLACE(item, 'mem', '') FROM #pNumbers )
Or as others have stated, you could open the csv in an external program and find and replace but atleast you have options

Is there any way to optimize this query?

I need to optimize the following query:
IF object_id('tempdb..#TAB001') IS NOT NULL
DROP TABLE #TAB001;
select *
into #TAB001
from dbo.uvw_TAB001
where 1 = 1
and isnull(COD_CUSTOMER,'') = isnull(#cod_customer,isnull(COD_CUSTOMER,''))
and isnull(TAXCODE,'') = isnull(#taxcode, isnull(TAXCODE,''))
and isnull(SURNAME,'') = isnull(#surname,isnull(SURNAME,''))
and isnull(VATCODE,'') = isnull(#vatCode,isnull(VATCODE,''))
The goal is to improve the performance of this query.
It is currently quite fast but I would like to speed it up even more.
This query has the optional parameters for which it is necessary to make a query that regardless of whether all or 1 parameter is set, returns results in the shortest possible time.
What you have here is known as a "catch-all" or "kitchen sink" query, which need a little helping hand sometimes.
Firstly, you need to get rid of those ISNULLs; they are making the query non-SARGable. Also, I would suggest getting rid of the SELECT * and limiting the query to the columns you need.
Then, finally, we can add OPTION (RECOMPILE) to the query; why is discussed in the articles I linked above. This gives you the following:
SELECT * --Replace with Column Names
INTO #TAB001 --Do you actually need to do this?
FROM dbo.uvw_TAB001
--Removed WHERE 1 = 1 as it's always true, thus pointless
WHERE (COD_CUSTOMER = #cod_customer OR #cod_customer IS NULL)
AND (TAXCODE = #taxcode OR #taxcode IS NULL)
AND (SURNAME = #surname OR #surname IS NULL)
AND (VATCODE = #vatCode OR #vatCode IS NULL)
OPTION (RECOMPILE);
Note I am assuming that when a variable (for example #cod_customer) has the value NULL you mean that the variable should be "ignored" and not matched against NULL.
If you actually want {Column} = #{Variable} including NULL then use SQL with the format below instead:
({Column} = #{Variable} OR ({Column} IS NULL AND #{Variable} IS NULL))

Update with wildcard

in need to update all the rows that have sub string like this:
'forcestartpage=xx'and replace it with 'forcestartpage=18'
* there is lots of characters before and after the substring that shouldnt change
tried this, doesnt work:
update t_reminderscont
set body = REPLACE (body,'forcestartpage=__','forcestartpage=18')
thanks
You can get away with a STUFF function:
SELECT
T.body,
Replaced = STUFF(
T.Body, -- Insert in T.Body
CHARINDEX('forcestartpage=', T.Body), -- ... at the position where 'forcestartpage=' starts
LEN('forcestartpage=18'), -- ... while replacing 17 characters
'forcestartpage=18') -- ... the value forcestartpage=18
FROM
YourTable AS T
WHERE
T.body LIKE '%forcestartpage=__%' AND
T.body NOT LIKE '%forcestartpage=18%'
However this will only work for the first appearance of the forcestartpage= on each row.

Cursor with a variable as a parameter Oracle

I have a function with a cursor. Within this cursor I want to get another cursor which I pass a parameter . This parameter is a value of the primary cursor. The logic that I have is like this:
CURSOR cursor1 IS
SELECT * FROM SCHEMAP.TABLA1 ;
registro cursor1%ROWTYPE;
CURSOR cursor2 (parametro IN NUMBER) IS
SELECT * FROM SCHEMAP.TABLA2 WHERE CAMPO_1 = parametro;
registroVac cursor2%ROWTYPE;
..........
BEGIN
.......
OPEN cursor1;
FETCH cursor1 INTO registro;
WHILE cursor1%found
LOOP
dbms_output.put_line('VARIABLE1:' + registro.VARIABLE1 );
OPEN cursor2(registro.VARIABLE1);
FETCH cursor2 INTO registroVac;
WHILE cursor2%found
LOOP
SELECT HC3PKDMUTILITIES.GET_DIAGNOSTIC_CODE_VAC(registro.VARIABLE1,registroVac.VAC_DOS,registroVac.VAC_CVH)
into v_diagnostic_code
from DUAL;
dbms_output.put_line('v_diagnostic_code -->' || v_diagnostic_code);
FETCH cursor2 INTO registroVac;
END LOOP;
CLOSE cursor2;
FETCH cursor1 INTO registro;
END LOOP;
CLOSE cursor1;
When I run the process I have an error in cursor2 like this:
ORA-06502: PL/SQL: numeric or value error: character to number conversion error CAMPO_1:102435313
CAMPO_1 is proven to be a numerical Database and registro.VARIABLE1 too. How to solve this problem?. Thanks.
Is this only a code-snipped and do you have more code in your application?
If not, then you can do it all in one which should be much faster and shorter:
CURSOR All_in_one IS
SELECT VARIABLE1,
HC3PKDMUTILITIES.GET_DIAGNOSTIC_CODE_VAC(registro.VARIABLE1,registroVac.VAC_DOS,registroVac.VAC_CVH) AS v_diagnostic_code
FROM SCHEMAP.TABLA2 t registroVac
RIGHT OUTER JOIN SCHEMAP.TABLA1 registro ON CAMPO_1 = VARIABLE1;
There are loads of things wrong with your code.
The thing that strikes me first is that you're opening cursor1, opening, fetching and closing cursor2, and then fetching from cursor1. That seems incorrect!
Secondly, why bother having two cursors and reinventing nested loop joins yourself? SQL is perfectly capable of handling joins, and the optimizer is pretty good at deciding which join to use (hash join, nested loops, etc).
Thirdly, if HC3PKDMUTILITIES.GET_DIAGNOSTIC_CODE_VAC is a function, why are you selecting it from dual (and therefore introducting context switching between the PL/SQL and SQL engines), rather than simply assigning the variable with the return value of the function?
I think you could rewrite the above code as simply:
declare
v_diagnostic_code varchar2(100); -- wasn't sure of the correct datatype; this is just a guess
begin
for rec in (select t1.variable1,
t2.vac_dos,
t2.vac_cvh
from schemap.tabla1 t1
inner join schemap.tabla2 t2 on (t2.campo_1 = t1.variable1))
loop
v_diagnostic_code := hc3pkdmutilities.get_diagnostic_code_vac(rec.variable1,rec.vac_dos,rec.vac_cvh);
dbms_output.put_line('variable1 --> '||rec.variable1||', v_diagnostic_code -->' || v_diagnostic_code);
end loop;
end;
/

getting data from memory instead of table

I have a parameter table with 10 rows. Called parameter_table.
In my PL/SQL procedure, I do loop in 2 million records. And each time querying this parameter table too.
I want to load this parameter table in to the memory and decrease the I/O process.
What is the best way to do this?
FOR cur_opt
IN (SELECT customer_ID,
NVL (customer_type, 'C') cus_type
FROM invoice_codes
WHERE ms.invoice_type='RT')
LOOP
....
...
Select data From parameter_table Where cus_type = cur_opt.cus_type AND cr_date < sysdate ; -- Where clause is much complex than this..
....
...
END LOOP;
You can just join it to your main query:
select customer_id, data
from parameter_table t, invoice_codes c
where t.cus_type = nvl(c.customer_type, 'C')
and t.cr_date < sysdate
However, if you've got 2 million records in invoice_codes, then joining to the parameter table is the least of your concerns - looping through this will take some time (and is probably the real cause of your I/O problems).
I Think you may change the query ,joining to parameter_table, so there will be no need to hit the select statement inside the loop. (like what #Chris Saxon solution)
But as a way to use cashed data,
You could fill a dictionary like, array and then refer it when necessary
Something like this may help:
you have to call Fill_parameters_cash before starting the main process and call get_parameter to fetch the data, the input parameter to call get_parameter is the dictionary key
TYPE ga_parameter_t IS TABLE OF parameter_table%ROWTYPE INDEX BY BINARY_INTEGER;
ga_parameter ga_parameter_t;
procedure Fill_parameters_cash is
begin
ga_parameter.DELETE;
SELECT * BULK COLLECT
INTO ga_parameter
FROM parameter_table;
end Fill_parameters_cash;
FUNCTION get_parameter(cus_type invoice_codes.cus_type%TYPE,
is_fdound OUT BOOLEAN)
RETURN parameter_table%ROWTYPE IS
result_value parameter_table%ROWTYPE;
pos NUMBER;
BEGIN
result_value := NULL;
is_fdound := FALSE;
IF cus_type IS NULL THEN
RETURN NULL;
END IF;
pos := ga_parameter.FIRST;
WHILE pos IS NOT NULL
LOOP
EXIT WHEN ga_parameter(pos).cus_type = cus_type;
pos := ga_parameter.NEXT(pos);
END LOOP;
IF pos IS NOT NULL THEN
is_fdound := TRUE;
result_value := ga_parameter(pos);
END IF;
RETURN result_value;
END get_parameter;
I'd guess looping through a million records is already causing issues. Not quite sure how this parameter table lookup is really worsening it.
Anyways, if this is really the only approach you can take, then you could do an inner or outer join in the cursor declaration.
----
FOR cur_opt
IN (SELECT customer_ID,
NVL (customer_type, 'C') cus_type
FROM invoice_codes codes,
parameter_table par
WHERE ms.invoice_type='RT'
and codes.cus_type = par.cus_type -- (or an outer join) maybe?
) loop
..........

Resources