select statements and loops - sql

I am trying to execute a program with the following flow. I wondered how I could write this properly with oracle pl/sql?
paymentIds is an array of values, originally initialized as a VARRAY.
I'd like to pass variable1 into the "update" statement.
procedure reset_finance_interface(paymentIds MyType)
is
BEGIN
FOR i IN 1..paymentIds.count LOOP
variable1 =
select id_finance_interface
from finance_interface fi
where fi.interface_id in (paymentIds(i))
and fi.id_interface_type = 'DC'
update finance_interface fi
set processed = 0
,id_interface_file = null
,interfaced=0
,interface_date = null
where
id_interface_type in ('DC')
and id_finance_interface = variable1
and processed = 2 --not in (0,1)
and ok_to_process = 1;
END LOOP;
END;
Thanks,
Robert

You can use a MERGE statement to get rid of the loops and combine the SELECT and UPDATE statements:
procedure reset_finance_interface(paymentIds MyType)
IS
BEGIN
MERGE INTO finance_interface dst
USING (
SELECT column_value AS id
FROM TABLE(paymentIDs)
) src
ON (
src.id = dst.interface_id
AND dst.id_interface_type = 'DC'
AND dst.processed = 2 --not in (0,1)
AND dst.ok_to_process = 1
)
WHEN MATCHED THEN
UPDATE
SET processed = 0
, id_interface_file = null
, interfaced = 0
, interface_date = null;
END;
/
db<>fiddle here

Related

Using different set of WHERE clauses in stored procedure depending on Parameter value

I have 2 stored procedures which return the same columns that I am trying to merge into a single procedure. They both have a different set of parameters and both have different WHERE clauses, but they use the same tables and select the exact same rows.
WHERE clause 1: (uses #UIOID, and #Level)
WHERE ( #UIOID = CASE WHEN #Level = 'Single' THEN C.C_UIOID_PK
WHEN #Level = 'Children' THEN CLC.UIOL_P
WHEN #Level = 'Parent' THEN CLP.UIOL_C
END
OR ( #UIOID = '0'
AND #Level = 'All'
)
)
Where clause 2: (Uses #TeamCode, #Year, #IncludeQCodes)
WHERE C.C_IsChild = 0
AND C.C_MOA <> 'ADD'
AND #TeamCode = C.C_OffOrg
AND C.C_Active = 'Y'
AND ( #Year BETWEEN dbo.f_GetAcYearByDate(C.C_StartDate) AND dbo.f_GetAcYearByDate(C.C_EndDate)
OR #Year = 0 )
AND ( C.C_InstCode NOT LIKE 'Q%'
OR #IncludeQCodes = 1 )
Ideally I want to add a new parameter which basically tells it which of the two WHERE clauses to run, but I can't seem to recreate that with CASE statement because as far as I can tell, they only work for a single WHERE clause, not a whole set of different clauses
I want to do this without having to repeat the select statement again and putting the whole thing in IF statements, and i don't want to put the query into a string either. I just want one select statement ideally.
The problem with using temp tables is the query itself takes a while to run without any parameters and is used in a live website, so I don't want it to have to put all records in a temp table and then filter it.
The problem with using a CTE is you can't follow it with an IF statement, so that wouldn't work either.
Here is the sort of logic I am trying to achieve:
SELECT A
B
C
FROM X
IF #WhichOption = 1 THEN
WHERE ( #UIOID = CASE WHEN #Level = 'Single' THEN C.C_UIOID_PK
WHEN #Level = 'Children' THEN CLC.UIOL_P
WHEN #Level = 'Parent' THEN CLP.UIOL_C
END
OR ( #UIOID = '0'
AND #Level = 'All'
)
)
ELSE IF #WhichOption = 2 THEN
WHERE C.C_IsChild = 0
AND C.C_MOA <> 'ADD'
AND #TeamCode = C.C_OffOrg
AND C.C_Active = 'Y'
AND ( #Year BETWEEN dbo.f_GetAcYearByDate(C.C_StartDate) AND dbo.f_GetAcYearByDate(C.C_EndDate)
OR #Year = 0 )
AND ( C.C_InstCode NOT LIKE 'Q%'
OR #IncludeQCodes = 1 )
Save the following process in a procedure. You can also directly insert into a physical table.
declare #varTable Table (columns exactly as Procedures return)
if(condition is met)
begin
insert into #varTable
exec proc1
end
else
begin
insert into #varTable
exec proc2
end
Add the parameter that you said that it would indicate what filter apply :
select XXXXX
from XXXXX
where (#Mode = 1 and ( filter 1 ))
or
(#Mode = 2 and ( filter 2 ))
option(recompile)
If the #Mode parameter is 1 then it will evaluate the filter 1, otherwise it will evaluate the filter 2.
Add an option(recompile) at the end of the statement, so the SQL engine will replace the variables with their values, eliminate the filter that won't be evaluated, and generate an execution plant for just the filter that you want to apply.
PS: Please notice that although these catchall queries are very easy to code and maintain, and generate a perfectly functional and optimal execution, they are not advised for high-demand applications. The option(recompile) forces the engine to recompile and generate a new execution plan at every execution and that would have a noticeable effect on performance if your query needs to be executed hundreds of times per minute. But for the occasional use it's perfectly fine.
Try to use dynamic SQL:
DECLARE #sql NVARCHAR(max), #where NVARCHAR(max), #WhichOption INT = 1;
SET #sql = 'SELECT A
B
C
FROM X';
IF #WhichOption = 1
SET #where = 'WHERE ( #UIOID = CASE WHEN #Level = ''Single'' THEN C.C_UIOID_PK
WHEN #Level = ''Children'' THEN CLC.UIOL_P
WHEN #Level = ''Parent'' THEN CLP.UIOL_C
END
OR ( #UIOID = ''0''
AND #Level = ''All''
)
)';
ELSE IF #WhichOption = 2
SET #where = ' WHERE C.C_IsChild = 0
AND C.C_MOA <> ''ADD''
AND #TeamCode = C.C_OffOrg
AND C.C_Active = ''Y''
AND ( #Year BETWEEN dbo.f_GetAcYearByDate(C.C_StartDate)
AND dbo.f_GetAcYearByDate(C.C_EndDate)
OR #Year = 0 )
AND ( C.C_InstCode NOT LIKE ''Q%''
OR #IncludeQCodes = 1 ) ';
SET #sql = CONCAT(#sql,' ', #where)
PRINT #sql
EXECUTE sp_executesql #sql

input parameter used in case statement in where clause

I have the following simplified stored procedure where based on on the input parameter, I need to then do a case in the where clause. It will not execute as it says: Incorrect syntax near '='
PROCEDURE [dbo].[DataInfo]
#Allowactive BIT = 1
AS
BEGIN
Select * from tbl1 1
where (CASE #Allowactive
WHEN 0 then (t.Isactive = 1) END
AND isSubmitted = 1
END
your where clause will be like below
where
CASE #Allowactive
WHEN 0 then t.Isactive END =1
AND isSubmitted = 1
You shouldn't use parameters in a query like this, as it messes up the query plan. When the right plan to use changes depending on the parameter, you need separate queries, or to force SQL to always recompile.
So do this instead:
create or alter procedure [dbo].[DataInfo] #Allowactive bit = 1
as
begin
if #Allowactive = 0
begin
Select * from tbl1 1
where Isactive = 1
AND isSubmitted = 1
end
else
begin
select * from tbl1 1
where isSubmitted = 1
end
end
Instead run separate queries.
Try to run the following and see the results:
SELECT *
FROM Tbl1 AS T
WHERE CASE #Allowactive
WHEN 0 THEN 1 ELSE #Allowactive END = T.Isactive
AND
isSubmitted = 1;
If you have 2012+ version then you could also do:
SELECT *
FROM Tbl1 AS T
WHERE IIF(#Allowactive = 0, 1, #Allowactive) = T.Isactive;
It seems Zaynul Abadin Tuhin directly answers your question.
But, I believe a case statement complicates what you want to achieve.
I think a query like this satisfies your desired outcome:
PROCEDURE [dbo].[DataInfo]
#Allowactive BIT = 1
AS
BEGIN
SELECT * FROM tbl1 t
WHERE (#Allowactive = 1 OR (#Allowactive = 0 AND t.Isactive = 1))
AND t.isSubmitted = 1
END

SQL Server : calling a stored procedure or not

I have a stored procedure that has one input parameter.
However, in the stored procedure, there is a condition that needs user's input (WHEN t.flag = 0).
Is there a way not to call a new stored procedure but does the same job?
I do not want to add another input parameter in [dbo].[UpdateTheRate]
itself because I have other processes going on in this stored procedure.
ALTER PROCEDURE [dbo].[UpdateTheRate] (#PID int)
AS
UPDATE t
SET t.rate =
CASE
WHEN t.flag = 1 THEN (select UnitRate
from RateTable
where state ='IL' and Term='20')
WHEN t.flag = 0 THEN EXEC [dbo.rate_procedure] --(USER enter rate)
FROM TblChargeTable t
WHERE t.PID = #PID
Something along these lines?
ALTER PROCEDURE [dbo].[UpdateTheRate] (#PID int)
AS
-- defer executing the procedure unless necessary
IF EXISTS (SELECT 1 FROM TblChargeTable WHERE flag = 0 and PID = #PID)
BEGIN
EXEC dbo.rate_procedure; -- get #user_rate via return code or out parameters perhaps
END
UPDATE t
SET t.rate =
CASE WHEN t.flag = 1 THEN (select UnitRate from RateTable where state ='IL' and Term='20')
WHEN t.flag = 0 THEN #user_rate END -- retrieved above
FROM TblChargeTable t
WHERE t.PID = #PID;

PL/SQL Procedure - ignore argument if null

I have a procedure that takes three arguments and then queries a table based on those arguments. Now one of them could be null and if it is, I'd like it to be ignored in the WHERE clause of the selection.
create or replace PROCEDURE Procedure1
(
COUNTRY IN VARCHAR2, MAKE IN VARCHAR2, SERIAL IN number
) AS
BEGIN
DECLARE
CURSOR c1 IS select v.ID from vehicle v
where v.country = COUNTRY AND
v.make = MAKE AND
((SERIAL IS NOT NULL AND v.serial = SERIAL) OR 1);
BEGIN
FOR e_rec IN c1 LOOP
DBMS_OUTPUT.PUT_LINE(e_rec.id);
END LOOP;
END;
END Procedure1;
I tried something like this but it doesn't work.
you can use the condition like
WHERE v.country = COUNTRY AND
v.make = MAKE AND
(SERIAL IS NULL or v.serial = SERIAL)
This will also work
WHERE v.country = COUNTRY AND
v.make = MAKE AND
((SERIAL IS NOT NULL AND v.Serial = SERIAL) OR SERIAL IS NULL)
try this - this is same as #Miller suggested just using NVL function
WHERE v.country = nvl(COUNTRY,v.country)
AND v.make = nvl(MAKE,v.make)
AND v.serial = nvl(SERIAL,v.serial)

cursor for sql server2005

This is my cursor procedure:
DECLARE C1 CURSOR LOCAL FOR
SELECT DISTINCT
PPTR_MATCH_REF_NO,
PPTR_LDGR_CODE,
PPTR_SLMAST_ACNO,
PPTR_PPN_STATUS
FROM GLAS_PPN_TRANSACTIONS
WHERE PPTR_COMP_CODE = #COMP_CODE
AND ISNULL(PPTR_PPN_STATUS, 'X') = 'V'
DECLARE #MATCH_REF_NO NUMERIC(10,0),
#LDGR_CODE VARCHAR(MAX),
#SLMAST_ACNO VARCHAR(MAX),
#PPN_STATUS VARCHAR(2),
#ACCT_NAME VARCHAR(MAX)
BEGIN
OPEN C1
FETCH NEXT FROM C1 INTO #MATCH_REF_NO,#LDGR_CODE,#SLMAST_ACNO,#PPN_STATUS
WHILE ##FETCH_STATUS =0
BEGIN
-- SET #MATCH_REF_NO = PPTR_MATCH_REF_NO
-- SET #LDGR_CODE = PPTR_LDGR_CODE
-- SET #SLMAST_ACNO = PPTR_SLMAST_ACNO
SELECT #ACCT_NAME = COAD_PTY_FULL_NAME
FROM GLAS_SBLGR_MASTERS,
GLAS_PTY_ADDRESS
WHERE SLMA_COMP_CODE = #COMP_CODE
AND SLMA_LDGRCTL_YEAR = DBO.GLAS_VALIDATIONS_GET_OPEN_YEAR(#COMP_CODE)
AND SLMA_LDGRCTL_CODE = #LDGR_CODE
AND SLMA_STATUS = 'A'
AND SLMA_ACNO = #SLMAST_ACNO
AND COAD_COMP_CODE = SLMA_COMP_CODE
AND COAD_ADDR_ID = SLMA_ADDR_ID
IF #PPN_STATUS = 'V'
BEGIN
SELECT #PPN_STATUS = 'VER'
END
FETCH NEXT FROM C1 INTO #MATCH_REF_NO,#LDGR_CODE,#SLMAST_ACNO,#PPN_STATUS
END
CLOSE C1
END
DEALLOCATE C1
END
How can I retrive #MATCH_REF_NO, #LDGR_CODE, #SLMAST_ACNO, #PPN_STATUS and #ACCT_NAME at the same time?
here 2 select statements is there how can i combine
You can simplify this by using a common-table expression (CTE) in SQL Server 2005 - you'll get something like:
WITH Select1 AS
(
SELECT DISTINCT
PPTR_MATCH_REF_NO,
PPTR_LDGR_CODE,
PPTR_SLMAST_ACNO,
PPTR_PPN_STATUS
FROM GLAS_PPN_TRANSACTIONS
WHERE PPTR_COMP_CODE = #COMP_CODE
AND ISNULL(PPTR_PPN_STATUS, 'X') = 'V'
)
SELECT
COAD_PTY_FULL_NAME
FROM
GLAS_SBLGR_MASTERS, GLAS_PTY_ADDRESS, Select1
WHERE
SLMA_COMP_CODE = Select1.COMP_CODE
AND SLMA_LDGRCTL_YEAR = DBO.GLAS_VALIDATIONS_GET_OPEN_YEAR(Select1.COMP_CODE)
AND SLMA_LDGRCTL_CODE = Select1.LDGR_CODE
AND SLMA_STATUS = 'A'
AND SLMA_ACNO = Select1.SLMAST_ACNO
AND COAD_COMP_CODE = SLMA_COMP_CODE
AND COAD_ADDR_ID = SLMA_ADDR_ID
What I cannot determine from the code you posted is how the GLAS_SBLGR_MASTERS and the GLAS_PTY_ADDRESS are joined (on what condition). Just specifying these two in the FROM clause should be avoided - use the standard ANSI SQL JOIN statements:
FROM GLAS_SBLGR_MASTERS
INNER JOIN GLAS_PTY_ADDRESS ON ???????
Marc