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;
/
Related
DECLARE
COUNTING1 NUMBER(1);
BEGIN
SELECT COUNT(VACATION_REMAINING_COUNT)
INTO COUNTING1
FROM VACATION
WHERE NAME = :P0_VNAME;
IF COUNTING1 > 0 THEN
SELECT VACATION_REMAINING_COUNT
FROM
(
SELECT ROW_NUMBER() OVER (ORDER BY CREATED DESC) ROW_ID,
V.VACATION_REMAINING_COUNT
FROM VACATION V
WHERE NAME = :P0_VNAME
)
WHERE ROW_ID = 1;
ELSE
SELECT USER_YEAR_VACATION FROM VA_USER WHERE NAME = :P0_VNAME;
END IF;
END;
ORA-06550: line 1, column 114: PLS-00103: Encountered the symbol "DECLARE" when expecting one of the following: ( - + case mod new not null continue avg count current exists max min prior sql stddev sum variance execute forall merge time timestamp interval date pipe
I wrote this sql code. but An error has occurred.
please help me..
You are missing the INTO clause for your second and third SELECT statements.
However, I would skip using the first COUNT statement and just try to find the latest row and catch a NO_DATA_FOUND exception if it occurs:
DECLARE
p_vacation_remaining VACATION.VACATION_REMAINING_COUNT%TYPE;
BEGIN
BEGIN
SELECT vacation_count_remaining
INTO p_vacation_remaining
FROM vacation
WHERE name = :P0_VNAME
ORDER BY created DESC
FETCH FIRST 1 ROW ONLY;
EXCEPTION
WHEN NO_DATA_FOUND THEN
SELECT USER_YEAR_VACATION
INTO p_vacation_remaining
FROM VA_USER
WHERE NAME = :P0_VNAME;
END;
-- Do something with p_vacation_remaining
DBMS_OUTPUT.PUT_LINE( p_vacation_remaining );
END;
/
I have a procedure that runs a select ( I tested that is good returns 56 records )
then when I run a cursor I want to pass 3 fields to a function ( see above ) that will
lookup/select a record from a table that contains 15 million records ( 10 years worth ).
It returns a rowtype that I want to then extract the fields from this rowtype record to
run an insert with both the records from the 1st select and the additional fields acquired
from the lookup function.
If I run the procedure the console prints out my test msgs but when I try to run
select * bulk collect into v_tab_proc_claim_recs from v_processed_claim;
it doesn't compile due to Error(97,65): PL/SQL: ORA-00942: table or view does not exist
as if either of these are not Tables.
Am I doing this right... how can I do it, why can't it see the table I'm trying to extract to ?
Should I do this some other way..
Thanks for any help/suggestions :)
The function is below....
create or replace function get_processed_claim_rec(
p_provider VARCHAR2,
p_rx VARCHAR2,
p_record_no NUMBER
)
return i_idb.processed_claim%rowtype
as
l_claim_record i_idb.processed_claim%rowtype;
begin
select * into l_claim_record from i_idb.processed_claim
where source_date = p_provider
AND rx = p_rx
AND rec_no = p_record_no;
return(l_claim_record);
end;
And the procedure is....
create or replace PROCEDURE import_mailer_data
AS
-------------------------------
/**
for the lookup table
**/
v_processed_claim i_idb.processed_claim%rowtype;
TYPE proc_claim_recs IS TABLE OF v_processed_claim%ROWTYPE INDEX BY PLS_INTEGER;
v_tab_proc_claim_recs proc_claim_recs;
--------------------------------
CURSOR myCursor
IS
SELECT *
from
(
SELECT
j.create_date as open_date,
case when (j.create_date < (sysdate - 20) )
then 'POD'
else 'REG'
end as priority,
c.division,
c.unit,
--p.refill as days_supply,
--p.din_name,
'CM_JOHN' as log_code,
c.first_name,
c.last_name,
--p.UNLISTED_compound,
--p.intervention_code,
--p.substitution,
--p.confirm,
c.PROVIDER,
c.rx,
c.DISPENSE_DATE,
c.DIN,
c.QTY,
c.DIN_COST_PAID,
c.DISP_FEE_PAID,
c.PAID_AMOUNT,
c.SOURCE_DATE,
c.RECORD_NO,
c.RELATIONSHIP,
c.INSURER_NO,
c.GROUP_NO,
c.CERTIFICATE,
c.BIRTH_DATE,
c.USER_ID,
--p.rej_code --v_seq_no
rank() over
(
partition by c.provider, c.rx, c.record_no Order by c.provider desc, c.rx desc
) as RNK
FROM AUDITCOLLECTIONS.MAILER_CLAIMS c,
AUDITCOLLECTIONS.MAILER_JOBS j
WHERE MAILER_JOB_DETAIL_ID IN
(SELECT MAILER_JOB_DETAIL_ID
FROM AUDITCOLLECTIONS.MAILER_JOB_DETAILS
WHERE MAILER_JOB_ID IN
( SELECT MAILER_JOB_ID FROM AUDITCOLLECTIONS.MAILER_JOBS
)
)
AND ( c.PROVIDER, c.rx, c.record_no ) NOT IN
( SELECT provider, rx, rec_no FROM AUDITCOLLECTIONS.COLLECTION_AUDIT_STAGING
)
AND j.create_date > (sysdate - 30)
AND c.provider = '2010500042'
) A_Latest
where A_Latest.RNK = 1;
BEGIN
v_report_id := audit_load.create_loaded_report(v_report_type_id);
FOR curRec IN myCursor
LOOP
BEGIN
dbms_output.put_line ('===>>>> PRINTING TEST1 = ');
v_processed_claim := get_processed_claim_rec(curRec.PROVIDER, curRec.RX, curRec.RECORD_NO);
select * bulk collect into v_tab_proc_claim_recs from v_processed_claim;
END LOOP;
audit_load.update_status_to_loaded(v_report_id);
END import_mailer_data;
You can do this:
FOR curRec IN myCursor
LOOP
v_processed_claim :=
get_processed_claim_rec(curRec.PROVIDER, curRec.RX, curRec.RECORD_NO);
v_tab_proc_claim_recs (v_tab_proc_claim_recs.COUNT+1) := v_processed_claim;
END LOOP;
Or simplify to:
FOR curRec IN myCursor
LOOP
v_tab_proc_claim_recs (v_tab_proc_claim_recs.COUNT+1) :=
get_processed_claim_rec(curRec.PROVIDER, curRec.RX, curRec.RECORD_NO);
END LOOP;
The below procedure is taking almost5 hours to complete 130000 records. Have tried optimizing it. Is there way to optimize it more?
If i commit after each "for all" , does that increase the performance?
Also i have given a limit of 1000 records, so here it is committing for 1000 record processing or when the count becomes 0?
database version : oracle 10g
I am running the below procedure :
create or replace PROCEDURE WeeklyClearQwAcctActivityLoad
AS
v_no_of_Days_retention number;
jobname VARCHAR2 (30);
loadstartdt DATE;
rcdcnt number;
errorcode NUMBER;
errormsg VARCHAR2 (100);
/* Identify those records for which all CUST_ACCT_ID under the same Parent_id are closed (before retention days ) */
CURSOR getdataforhist
IS
select /*+ parallel(qa2,128) */ CUST_ACCT_ID from qw_account qa2
where exists
( select /*+ parallel(qaa2,128) */ 1 from QW_ACCT_ACTIVITY qaa2
where qaa2.cust_acct_id = qa2.cust_acct_id
and qaa2.actvy_end_date < sysdate - v_no_of_Days_retention
)
and not exists
(
select 1 from (
select /*+ parallel(qa,128) */ qa.PARENT_ID pidd from qw_account qa
where exists
( select /*+ parallel(qaa,128) */ 1 from QW_ACCT_ACTIVITY qaa
where qaa.cust_acct_id = qa.cust_acct_id
and qaa.actvy_end_date > sysdate - v_no_of_Days_retention
)
) pp where pp.pidd = qa2.PARENT_ID
);
TYPE t_getDataForHist IS TABLE OF qw_acct_activity.cust_acct_id%TYPE;
l_getDataForHist t_getDataForHist;
CURSOR orph_product
IS
SELECT /*+ parallel( ram , 128) */ ram.rcr_prod_acct_id
FROM rcr_acct_mapping ram
WHERE 1=1
AND ram.cust_acct_id IS NOT NULL
AND EXISTS
( SELECT /*+ parallel( rap , 128) */ 1
FROM rcr_acct_profile rap
WHERE rap.rcr_prod_acct_id = ram.rcr_prod_acct_id
AND rap.cust_acct_id = ram.cust_acct_id
AND rap.prod_acct_status in ('ACTIVE','INACTIVE','SUSPENDED')
)
AND NOT EXISTS
( SELECT /*+ parallel( qaa , 128 */ 1
FROM qw_acct_activity qaa
WHERE qaa.cust_acct_id = ram.cust_acct_id
);
TYPE t_orph_product is table of rcr_acct_mapping.rcr_prod_acct_id%TYPE;
l_orph_product t_orph_product;
cnt number default 0;
BEGIN
jobname := 'WEEKLY_CLEAN_QW_ACCT_ACTIVITY';
loadstartdt := SYSDATE;
rcdcnt := 0;
INSERT INTO rcr_stage_audit (job_name,load_start_date,load_end_date,record_cnt,processed,process_date,process_cnt,ignore_cnt)
VALUES (jobname,loadstartdt,NULL,NULL,'N',loadstartdt,NULL,NULL );
COMMIT;
BEGIN
SELECT VALUE into v_no_of_Days_retention
FROM rcr_online_svc_app_config
WHERE NAME = 'noofdaystoenddateqwacctactivity';
EXCEPTION
WHEN NO_DATA_FOUND
THEN
errorcode := SQLCODE;
errormsg := 'no of days to end date qw_accta_ctivity is not defined in rcr_code_translation table';
raise_application_error (-20101, errorcode || ' - ' || errormsg, TRUE);
END;
OPEN getDataForHist;
LOOP
FETCH getdataforhist BULK COLLECT INTO l_getdataforhist LIMIT 1000;
--EXIT WHEN getdataforhist%NOTFOUND ;
EXIT WHEN l_getdataforhist.COUNT = 0;
-- FORALL indx IN 1 .. l_getdataforhist.count
-- insert into TEMPSLOT (CUST_ACCT_ID) values ( l_getdataforhist(indx) ) ;
FORALL indx1 IN 1 .. l_getdataforhist.count
INSERT INTO qw_acct_activity_hist
SELECT qaa.*, SYSDATE
FROM qw_acct_activity qaa
WHERE CUST_ACCT_ID = ( l_getdataforhist(indx1) );
FORALL indx2 IN 1 .. l_getdataforhist.count
DELETE FROM qw_acct_activity
WHERE CUST_ACCT_ID = ( l_getdataforhist(indx2) );
rcdcnt := rcdcnt + sql%rowcount;
COMMIT;
END LOOP;
CLOSE getDataForHist;
--- Clean porduct tables for orphan CUST_ACCT_ID
OPEN orph_product;
LOOP
FETCH orph_product BULK COLLECT INTO l_orph_product LIMIT 1000;
EXIT WHEN l_orph_product.COUNT = 0;
FORALL indx10 IN 1 .. l_orph_product.COUNT
INSERT INTO rcr_acct_mapping_hist
SELECT a.*
FROM rcr_acct_mapping a
WHERE rcr_prod_acct_id = ( l_orph_product(indx10) );
FORALL indx11 IN 1 .. l_orph_product.COUNT
DELETE FROM rcr_acct_mapping WHERE rcr_prod_acct_id = ( l_orph_product(indx11) );
FORALL indx12 IN 1 .. l_orph_product.COUNT
DELETE FROM rcr_addt_acct_prof_detail WHERE rcr_prod_acct_id = ( l_orph_product(indx12) );
FORALL indx13 IN 1 .. l_orph_product.COUNT
DELETE FROM rcr_acct_profile_detail WHERE rcr_prod_acct_id = ( l_orph_product(indx13) );
FORALL indx14 IN 1 .. l_orph_product.COUNT
DELETE FROM rcr_acct_profile WHERE rcr_prod_acct_id = ( l_orph_product(indx14) );
COMMIT;
END LOOP;
close orph_product;
UPDATE rcr_stage_audit
SET load_end_date = SYSDATE,
record_cnt = rcdcnt,
processed = 'Y'
WHERE job_name = jobname
AND process_date = loadstartdt
AND load_start_date = loadstartdt;
COMMIT;
EXCEPTION
WHEN OTHERS
THEN
errorcode := SQLCODE;
errormsg := substr(sqlerrm,1,255);
raise_application_error (-20102, errorcode || ' - ' || errormsg, TRUE);
END WeeklyClearQwAcctActivityLoad;
One suggestion that I would recommend to you is to avoid explicit looping and cursors. It leads to poor performance, especially when you can directly use
insert into <table_name>(columns) select <your_query_goes_here>
This is most certainly going to perform faster than your looping constructs. In fact you can reproduce this behavior with simple benchmarks in a table generated with a million records.
So in short try to avoid looping and your code would also look more readable and less prone to errors.
I did a benchmark once where out of 10 million records only about 12,000 had to be updated and timing of explicit looping vs implicit looping lead was 1 minute 10 seconds v/s 1 second.
trace it using oracle tools like as oradebug or dbms_monitor and using tkprof or other analysis tools check the trace file.do the below:
1.extract the sid
2.in sqlplus run: oradebug setorapid xxxx
3.in sqlplus run: oradebug tracefile_name
4.after the process complete in os run tkprof on trace file.(other tools is available also).
5.in trace file check long sections and work on them
I have a function where i am summing the value of all sale_lines attached to a sale_head by sale_number. The problem is, the function will only return one sum, whereas I need it to return all sale_head sums in a specific time frame...
create or replace function sale_line_accounts
return number is
total_value_all number(38, 2);
value_sales number(12, 2);
last_month date;
this_month date;
sumPrice number(12,2);
-- type array_s is varray(200) of varchar2(30);
-- sums array_s := array_s();
begin
--------------------------------------
last_month := to_date('01/08/16');
this_month := to_date('03/08/16');
--------------------------------------
FOR headers IN
(
select sale_num, sale_date, status
from sale_head
where status = 'S' AND sale_date BETWEEN last_month AND this_month
) LOOP
-------------------------------------------
--sums.extend();--extend array
sumPrice:= 0;
FOR lines IN
(
select sale_num, quantity, actual_price
from sale_line
where sale_num = headers.sale_num
)LOOP
sumPrice := sumPrice + (lines.quantity * lines.actual_price);
dbms_output.put_line(sumPrice);
-- sums(sumPrice) := lines.sale_num;
END LOOP;
------------------------------------------
END LOOP;
-------------------------------------------
return sumPrice;
END;
/
the commented code was meant to create a collection or something? Please help!!
You can probably get your answer by just using a single SQL query:
select headers.sale_num
,sum(lines.quantity * lines.actual_price) price
from sale_head headers
join sale_line lines
on lines.sale_num = headers.sale_num
where headers.status = 'S'
and headers.sale_date between to_date('01/08/2016', 'DD/MM/YYYY') and to_date('03/08/2016', 'DD/MM/YYYY')
group by headers.sale_num
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;