Hi I have a scenario where in using a cursor loop getting all the invoice values and checking the details and updating flag values to 'E' if the update validation is satisfied and only inserting those invoices to another table which doesn't satisfy the update statement.
Is there a way by which based on the flag value we can insert those invoices?
Kindly find the Code:
Procedure
CURSOR c2
IS
SELECT *
FROM invoice_tl
WHERE process_flag = 'N';
BEGIN
FOR rec IN c2
LOOP
BEGIN
fnd_file.put_line (fnd_file.LOG, 'The Line Number is ' || ' ' || rec.line_number);
IF rec.line_number IS NOT NULL
THEN
UPDATE invoice_tl
SET process_flag = 'E',
error_description =
(SELECT 'Credit Memo line amount cannot be more than Invoice Line Amount : '
|| (rctl.extended_amount
- NVL (
(SELECT SUM (amount)
FROM ar_activity_details
WHERE customer_trx_line_id =
rctl.customer_trx_line_id),
0)
+ NVL (
(SELECT SUM (extended_amount)
FROM ra_customer_trx_lines_all
WHERE previous_customer_trx_line_id =
rctl.customer_trx_line_id),
0))
FROM ra_customer_trx_all rct,
ra_customer_trx_lines_all rctl
WHERE rct.customer_trx_id =
rctl.customer_trx_id
AND rct.org_id = 2326
AND rct.trx_number = rec.invoice_number
AND rctl.line_number = rec.line_number
AND rct.cust_trx_type_id =
ln_trans_type_id)
WHERE process_flag = 'N'
AND invoice_number = rec.invoice_number
AND line_number = rec.line_number
AND amount >
(SELECT (rctl.extended_amount
- NVL (
(SELECT SUM (amount)
FROM ar_activity_details
WHERE customer_trx_line_id =
rctl.customer_trx_line_id),
0)
+ NVL (
(SELECT SUM (extended_amount)
FROM ra_customer_trx_lines_all
WHERE previous_customer_trx_line_id =
rctl.customer_trx_line_id),
0))
FROM ra_customer_trx_all rct,
ra_customer_trx_lines_all rctl
WHERE rct.customer_trx_id =
rctl.customer_trx_id
AND rct.org_id = 2326
AND rct.trx_number =
rec.invoice_number
AND rctl.line_number =
rec.line_number
AND rct.cust_trx_type_id =
ln_trans_type_id);
fnd_file.put_line (
fnd_file.LOG,
'Error Message if the CM amount more than the Invoice Line amount.');
COMMIT;
END IF;
END;
BEGIN
fnd_file.put_line (
fnd_file.LOG,
'The Process FLag is : ' || rec.process_flag);
INSERT INTO second_table (
customer_number,
orig_system_cust_reference,
orig_system_add_reference,
customer_name,
locations,
inv_date,
creation_date,
inv_num,
balance_amount,
customer_trx_id,
customer_trx_line_id,
NAME,
term_desc,
term_id,
gl_date,
rec_segments1,
rec_segments2.....
END;
END LOOP;
END
Your best bet is to use the RETURNING INTO clause. So you'll define an array and capture the appropriate parts of the updated rows:
declare
type line_number_tt is table of invoice_tl.line_number%TYPE;
line_number_array line_number_tt;
begin
....
update invoice_tl
...
returning line_number bulk collect into line_number_array;
[do stuff with the array here]
end;
I would really try to get rid of the select-then-loop you have, if you can. That's row by row processing and there's a reason it's called "slow-by-slow."
Related
I have below procedure giving me error as
Error(17,3): PLS-00103: Encountered the symbol "FOR" when expecting one of the following: ( - + case mod new not null select with continue avg count current exists max min prior sql stddev sum variance execute fora
Here is the procedure.
PROCEDURE DeactiveUsers (
P_DeactiveUsers_OUT OUT SYS_REFCURSOR ) AS
BEGIN
OPEN P_DeactiveUsers_OUT FOR
for P_DeactiveUsers_Lst in(
select * from (
select username, MAX(TRANSACTION_DATE) As last_login_date
from r4g_application_activity_log
Group By username
) where last_login_date <= sysdate-90
order by 2 desc
)
update r4g_application_activity_log
set ISACTIVE = 1
where USERNAME = P_DeactiveUsers_OUT.username;
EXCEPTION
WHEN no_data_found THEN
INS_UMS_ERRORLOG(SQLCODE||' : '||SUBSTR(SQLERRM, 1, 200),null,'DeactiveUsers',null,null,null,'DB : DeactiveUsers','Scheduler - UMS_DeactiveUser');
WHEN others THEN
INS_UMS_ERRORLOG(SQLCODE||' : '||SUBSTR(SQLERRM, 1, 200),null,'DeactiveUsers',null,null,null,'DB : DeactiveUsers','Scheduler - UMS_DeactiveUser');
END DeactiveUsers;
Hm, yes - procedure is here, but - what is its purpose? The way you put it, it seems that it shouldn't return anything so you don't really want to open a ref cursor, but use a cursor FOR loop which then updates the log table.
If that's so,
remove OUT parameter
remove OPEN clause (btw. you've got two FORs)
use FOR loop
remove WHEN NO_DATA_FOUND as there's nothing that could raise it
PROCEDURE DeactiveUsers -- (P_DeactiveUsers_OUT OUT SYS_REFCURSOR)
AS
BEGIN
--OPEN P_DeactiveUsers_OUT FOR
FOR P_DeactiveUsers_Lst
IN ( SELECT *
FROM ( SELECT username, MAX (TRANSACTION_DATE) AS last_login_date
FROM r4g_application_activity_log
GROUP BY username)
WHERE last_login_date <= SYSDATE - 90
ORDER BY 2 DESC)
LOOP
UPDATE r4g_application_activity_log
SET ISACTIVE = 1
WHERE USERNAME = P_DeactiveUsers_OUT.username;
END LOOP;
EXCEPTION
-- WHEN no_data_found THEN
-- INS_UMS_ERRORLOG(SQLCODE||' : '||SUBSTR(SQLERRM, 1, 200),null,'DeactiveUsers',null,null,null,'DB : DeactiveUsers','Scheduler - UMS_DeactiveUser');
WHEN OTHERS
THEN
INS_UMS_ERRORLOG (SQLCODE || ' : ' || SUBSTR (SQLERRM, 1, 200),
NULL,
'DeactiveUsers',
NULL,
NULL,
NULL,
'DB : DeactiveUsers',
'Scheduler - UMS_DeactiveUser');
END DeactiveUsers;
[EDIT]
As you want to return list of deactivated users, then you could do it as follows: instead of a ref cursor, just loop through result set, do the update and return a collection of deactivated users:
PROCEDURE deactiveusers (p_deactivataed OUT SYS.odcivarchar2list)
IS
l_deactivated SYS.odcivarchar2list := sys.odcivarchar2list ();
BEGIN
FOR cur_r
IN ( SELECT *
FROM ( SELECT username, MAX (TRANSACTION_DATE) AS last_login_date
FROM r4g_application_activity_log
GROUP BY username)
WHERE last_login_date <= SYSDATE - 90
ORDER BY 2 DESC)
LOOP
UPDATE r4g_application_activity_log
SET isactive = 1
WHERE username = cur_r.username;
l_deactivated.EXTEND;
l_deactivated (l_deactivated.LAST) := cur_r.username;
END LOOP;
p_deactivated := l_deactivated;
END;
You'd call it as e.g.
DECLARE
l_deactivated SYS.odcivarchar2list;
BEGIN
deactiveusers (l_deactivated);
FOR i IN l_deactivated.FIRST .. l_deactivated.LAST
LOOP
DBMS_OUTPUT.put_line (l_deactivated (i));
END LOOP;
END;
/
Following query is used in a procedure. 1st insert happening quickly but 2nd insert taking a long time . The First For Loop query returns 5000 records which is then looped through another query which returns 4000 records and then performs 2nd insert based on a function return value which is taking 15 mins to execute . All the tables used are indexed need help on optimize the query ?
declare
LV_INCT_ROLE sy_employee_master.incentive_role%type;
BEGIN
FOR ASM1 IN (SELECT a.run_id,
a.emp_no emp_no,
a.team_id own_team_id,
b.team_id team_team_id,
a.incentive_role
FROM SY_HLSIL_ASM_EMP a,
SY_DSA_ASM_TEAMWISE_HIERARCHY b
WHERE a.emp_no = b.emp_no
AND a.run_id = b.run_id
AND b.run_id = 195) LOOP
BEGIN
INSERT INTO SY_DSA_ASM_TEAMWISE
(FROM_DATE,
TO_DATE,
RUN_ID,
EMP_NO,
INCENTIVE_ROLE,
TEAM_ID,
SUM_FOR_TEAMID)
SELECT '01-jan-2021',
'31-jan-2021',
195,
ASM1.EMP_NO,
ASM1.INCENTIVE_ROLE,
ASM1.OWN_TEAM_ID,
ASM1.EMP_NO
FROM DUAL
WHERE EXISTS (SELECT 'x'
FROM SY_DSA_TRANS_HLSIL H
WHERE H.RUN_ID = 195
AND NVL(H.CALC_INCT, 'Y') = 'Y'
AND NVL(H.HDFC_REACH_FLAG, 'N') = 'N'
AND H.EMP_NO = ASM1.EMP_NO)
AND NOT EXISTS
(SELECT 'x'
FROM SY_DSA_ASM_TEAMWISE D
WHERE D.RUN_ID = 195
AND D.SUM_FOR_TEAMID = TO_CHAR(ASM1.EMP_NO));
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Ins Tm err 2: ' || SQLERRM(-SQLCODE));
raise_application_error(-20000,SQLERRM(-SQLCODE));
END;
dbms_output.put_line('1st insert done');
FOR ASM IN (SELECT ASM1.EMP_NO EMP_NO,
ASM1.INCENTIVE_ROLE INCENTIVE_ROLE,
ASM1.OWN_TEAM_ID,
-- P.TEAM_ID TEAM_TEAM_ID,
P.REPORTEE_EMP_NO REPORTEE_EMP_NO
FROM SY_DSA_ASM_POPULATE_HIERARCHY P
WHERE p.FLAG = 'LOWER'
AND P.EMP_NO = ASM1.EMP_NO
AND P.RUN_ID = ASM1.RUN_ID
AND P.RUN_ID = 195) LOOP
LV_INCT_ROLE := UPPER(package.function
(ASM.REPORTEE_EMP_NO,'31-jan-2021');
IF INSTR(package.fucntion('INCT_RL_TL_ABOV'),UPPER(TRIM(LV_INCT_ROLE))) > 0
THEN
BEGIN
INSERT INTO SY_DSA_ASM_TEAMWISE
(FROM_DATE,
TO_DATE,
RUN_ID,
EMP_NO,
INCENTIVE_ROLE,
TEAM_ID,
SUM_FOR_TEAMID)
SELECT '01-jan-2021',
'31-jan-2021',
195,
ASM.EMP_NO,
ASM.INCENTIVE_ROLE,
ASM.OWN_TEAM_ID,
ASM.REPORTEE_EMP_NO
FROM DUAL
WHERE EXISTS (SELECT 'x'
FROM SY_DSA_TRANS_HLSIL H
WHERE H.RUN_ID = 195
AND NVL(H.CALC_INCT, 'Y') = 'Y'
AND NVL(H.HDFC_REACH_FLAG, 'N') = 'N'
AND H.EMP_NO = ASM.REPORTEE_EMP_NO)
AND NOT EXISTS
(SELECT 'x'
FROM SY_DSA_ASM_TEAMWISE D
WHERE D.RUN_ID = 195
AND D.EMP_NO = ASM.EMP_NO
AND D.SUM_FOR_TEAMID =
TO_CHAR(ASM.REPORTEE_EMP_NO));
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Ins Tm err 3: ' || SQLERRM(-SQLCODE));
END;
END IF;
END LOOP;
END LOOP;
dbms_output.put_line('2nd insert done');
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Ins Tm err 4: ' || SQLERRM(-SQLCODE));
END;
I am attempting to use a loop in my Oracle SQL code that will change the name of the schema slightly each time the loop is run. I have tried the SQL code below, creating a NUMBER variable that counts up from 1 to 3 and then concatenating it with the schema name, but I keep receiving a long error message. The schema name should be 'x_rm_mt1_d' the first loop, 'x_rm_mt2_d' the second loop, and 'x_rm_mt3_d' on the final loop. The select statement in the code below is just a small example of what I am trying to do, I didn't think it would be pertinent to include the entire query that I am looking to use the variable for.
DECLARE
l_counter NUMBER := 0;
BEGIN
LOOP
l_counter := l_counter + 1;
IF l_counter > 3 THEN
EXIT;
END IF;
DEFINE StrSchema = 'x_rm_mt' || l_counter || '_d'
WITH aed AS (
SELECT DISTINCT SSN , STATE FROM (
--Effective Date During Quarter
SELECT *
FROM
(SELECT * FROM ADDRESS_EFF_DATE
WHERE STATE = 'VT'
AND EFF_DATE >= '01-JAN-20'
AND EFF_DATE < '01-APR-20'
AND ADDRESS_KEY = '0'
)aed
WHERE aed.EFF_DATE = (
SELECT MAX(aed2.EFF_DATE)
FROM ADDRESS_EFF_DATE aed2
WHERE aed2.CONTROL_ID = aed.CONTROL_ID
AND aed2.SSN = aed.SSN)
--Effective Date Prior to Quarter
UNION
SELECT *
FROM
(SELECT *
FROM Strschema.ADDRESS_EFF_DATE
WHERE STATE = 'VT'
AND EFF_DATE < '01-JAN-20'
AND ADDRESS_KEY = '0') aed
WHERE aed.EFF_DATE = (
SELECT MAX(aed1.EFF_DATE)
FROM Strschema.ADDRESS_EFF_DATE aed1
WHERE aed.ssn=aed1.ssn
AND aed.EFF_DATE < '01-JAN-20'
AND aed1.EFF_DATE < '01-JAN-20')) )
,
--Select all records from Employee Eff Date Where Latest Hire Date is before 4/1/20
--AND Term Date is Null or Term Date is Greater than 1/1/20 eed AS (
SELECT *
FROM
(SELECT *
FROM Strschema.EMPLOYEE_EFF_DATE eed
WHERE eed.CONTROL_ID = 'SMLMKT'
AND eed.EFF_DATE = (
SELECT MAX(eed1.EFF_DATE)
FROM Strschema.EMPLOYEE_EFF_DATE eed1
WHERE eed.SSN = eed1.SSN
AND eed1.CONTROL_ID = 'SMLMKT')
) eed3
WHERE eed3.LATEST_HIRE_DATE <= '04-APR-20'
AND (eed3.LAST_TERM_DATE > '01-JAN-20'
OR eed3.LAST_TERM_DATE is NULL) ) ,
ebe AS (
SELECT *
FROM Strschema.emp_ben_elects ebe
WHERE ebe.control_id = 'SMLMKT'
AND ebe.BENEFIT_ID = 'MEDICAL'
AND ebe.life_event_date = (
SELECT MAX(x.life_event_date)
FROM Strschema.employee_life_events x
WHERE x.ssn = ebe.ssn
AND x.control_id = 'SMLMKT'
AND ebe.p_company_id_i = x.p_company_id_i
AND x.life_event_status = 'C')
AND ebe.le_seq_no = (
SELECT MAX(x.le_seq_no)
FROM Strschema.employee_life_events x
WHERE x.ssn = ebe.ssn
AND x.control_id = 'SMLMKT'
AND ebe.p_company_id_i = x.p_company_id_i
AND x.life_event_status = 'C'
AND ebe.life_event_date = x.life_event_date)
)
SELECT cmp.NAME as "Client Name" , cssn.REAL_SSN as "Employee SSN"
--, aed.SSN as "FAKE SSN REMOVE" , eed.LAST_NAME as "Last Name" , eed.FIRST_NAME as "First Name" , aed.STATE as "Resident State" , eed.LATEST_HIRE_DATE as "Hire Date" , pi.DESCR1 as "Plan Name" , ebe.OPTION_ID as "Tier" , ebe.BENEFIT_EFF_DATE as "Coverage Start Date" , eed.LAST_TERM_DATE as "Coverage End Date"
--, eed.LAST_TERM_DATE
FROM eed INNER JOIN aed ON eed.SSN = aed.SSN
LEFT JOIN ebe ON eed.SSN = ebe.SSN
JOIN Strschema.COMP_SSN cssn ON eed.SSN = cssn.SSN
LEFT JOIN Strschema.PLAN_INFO pi ON ebe.PLAN_ID = pi.PLAN_ID AND ebe.BENEFIT_ID = pi.BENEFIT_ID
JOIN Strschema.COMPANY cmp ON eed.CURRENT_CO = cmp.COMPANY_ID
END LOOP;
END;
DECLARE the variable and then set its value in the loop:
DECLARE
TYPE employee_array IS TABLE OF EMPLOYEE%ROWTYPE;
-- Assuming the tables all have the same type.
l_StrSchema VARCHAR2(30);
t_employees employee_array;
BEGIN
FOR l_counter IN 1 .. 3 LOOP
l_StrSchema := 'x_rm_mt' || l_counter || '_d';
DBMS_OUTPUT.PUT_LINE( 'Loop ' || l_counter );
EXECUTE IMMEDIATE 'SELECT * FROM ' || l_Strschema || '.EMPLOYEE'
|| ' WHERE ROWNUM < 1000'
BULK COLLECT INTO t_employees;
FOR i IN 1 .. t_employees.COUNT LOOP
DBMS_OUTPUT.PUT_LINE( t_employees(i).name );
END LOOP;
END LOOP;
END;
/
You also need to use dynamic SQL if you are dynamically setting the table's schema and will need to collect the rows into a data structure as you are working in PL/SQL (and not in the SQL scope). You can also use a FOR loop.
db<>fiddle
Hi I'm trying the code the below logic..i need help..
When i run the following procedure i get all the sids along with the corresponding pid for a particular month. but when i uncomment the parts that i have commented here i get the month and year displayed and then a message saying 'no data found'. Where am i going wrong?
create or replace PROCEDURE mas(V_MONTH NUMBER DEFAULT NULL,V_YEAR NUMBER DEFAULT NULL,V_AID VARCHAR2) AS
V_MID VARCHAR2(50);
V_SID VARCHAR2(50);
v_v_month number := nvl(V_MONTH,to_number(to_char(sysdate,'mm')));
v_v_year number := nvl(V_YEAR,to_number(to_char(sysdate,'yyyy')));
v_is_sub PM.IS_SUB%TYPE;
V_DIST_s NUMBER;
V_DIST_t NUMBER;
cursor c1
is
select distinct a.mid,
b.sid
from pmt a
inner join smt b
on (a.mid = b.mid)
where a.AID = V_AID
AND A.AID = B.AID
AND EXTRACT(MONTH FROM A.RDATE)= v_v_month AND
EXTRACT(YEAR FROM A.RDATE)= v_v_year
order by mid;
BEGIN
dbms_output.put_line('month : ' || v_v_month);
dbms_output.put_line('year : ' || v_v_year);
/*
select IS_SUB into v_is_sub from program_master where pid = 'V_AID';
IF v_is_sub = 1 then
select count(*) into V_DIST_S from (select distinct sid from smt where aid = 'v_aid');
select count(*) into V_DIST_T from (select distinct sid from tm where aid = 'v_aid');
if(V_DIST_S = V_DIST_T) then
*/
for rec1 in c1
loop
dbms_output.put_line('MID : ' || rec1.MID);
dbms_output.put_line('SID : ' || rec1.SID);
end loop;
-- else
-- dbms_output.put_line('count of sids do not match');
--end if;
--else
--dbms_output.put_line('No sids available for the mentioned pid.');
--end if;
END MAS;
where pid = 'V_AID';
V_AID is a variable, however, you have enclosed it within single-quotation marks, which makes it a string. So, you are actually looking for the value 'V_AID' and not the value of the variable.
Modify it to:
select IS_SUB into v_is_sub from program_master where pid = V_AID;
And do the same wherever you have enclosed the variable in single-quotation marks.
for this particular block, i am continuously getting
ora 0142 : exact fetch returns more than requested number of rows
, i have tried distinct, rank and rownum, but nothing seems to work.
begin
for i in c1 loop
if i.estacao_a2 is not null then
begin
select migrationidentifier
into v_master_location
from (
select com.migrationidentifier
, row_number () over (partition by com.migrationidentifier order by com.migrationidentifier asc) RK
from com_location com
where round (i.latitude_a_decimal, 1) =
round (com.LATITUDEWGS84, 1)
and round (i.longitude_a_decimal, 1) =
round (com.longitudewgs84, 1)
and com.sourcedomain = 'FENIX'
)
where rk=1
;
exception
when no_data_found
then dbms_output.put_line ( 'NO RECORDS FOUND IN COM_LOCATION FOR LATITUDE:' || i.latitude_a_decimal);
end;
end if;
end loop;
end;
OK, so you have more than one migrationidentifier in com_location for that set of latitude_a_decimal and longitude_a_decimal. Is this bad data? Or possible? Or there is some ordering criteria that will determine which one are you supposed to take?
If there is an ordering criteria - add that to your query then put the query into a cursor and do an OPEN...FETCH INTO ... CLOSE to grab that row first and populate your variable. You won't need your EXCEPTION block doing it this way, you instead after the fetch do IF cursorname%NOTFOUND THEN dbms_output() ENDIF;
declare
cursor get_migrationidentifier (in_lat_decimal number, in_long_decimal number)
IS
select migrationidentifier from
(select com.migrationidentifier
,row_number () over (partition by com.migrationidentifier order by com.migrationidentifier asc) RK
from com_location com
where round (i.latitude_a_decimal, 1) =
round (com.LATITUDEWGS84, 1)
and round (i.longitude_a_decimal, 1) =
round (com.longitudewgs84, 1)
and com.sourcedomain = 'FENIX') where rk=1
order by migrationidentifier ;
begin
for i in c1
loop
if i.estacao_a2 is not null then
OPEN get_migrationidentifier (i.latitude_a_decimal. i.longitude_a_decimal);
FETCH get_migrationidentifier INTO v_master_location;
IF get_migrationidentifier%NOTFOUND
THEN v_master_location := null;
dbms_output.
put_line (
'NO RECORDS FOUND IN COM_LOCATION FOR LATITUDE:'
|| i.latitude_a_decimal);
end IF;
CLOSE get_migrationidentifier;
end if;
end loop;