How to continue when no_data_found exception raised? - oracle

I have a value that i dont know exactly in which column it is inserted. I can determine that since this table columns are named as C1....C99. I am going to find the column using the following code. But when the no data found exception is called, I cant start my loop again.
DECLARE
i number:=1;
k boolean := true;
output number;
stmt varchar(500);
BEGIN
<<repeat>>
while(k)
loop
DBMS_OUTPUT.PUT_LINE( 'c column -->'||i );
EXECUTE IMMEDIATE 'select 1 from X_TAB t where t.c'||i||'= ''NOTE_NFE'''
into output;
IF output = 1 then
DBMS_OUTPUT.PUT_LINE( 'c column'||i );
k:=false;
END IF;
i:=i+1;
IF i = 100 then
k:=false;
END IF;
END LOOP;
EXCEPTION
when no_data_found then
i:=i+1;
if i = 100 then
k:=false;
end if;
goto repeat;
END;
/

I think that moving your try catch to inside the loop will do the trick for you.
DECLARE
i number:=1;
k boolean := true;
output number;
stmt varchar(500);
BEGIN
<<repeat>>
while(k)
loop
DBMS_OUTPUT.PUT_LINE( 'c column -->'||i );
begin
EXECUTE IMMEDIATE 'select 1 from X_TAB t where t.c'||i||'= ''FISCAL_NOTE_NFE''' into output;
exception when no_data_found then
output := 0; --set a default value
dbms_output.put_line('no data found.');
end;
IF output = 1 then
DBMS_OUTPUT.PUT_LINE( 'c column'||i );
k:=false;
END IF;
i:=i+1;
IF i = 100 then
k:=false;
END IF;
END LOOP;
END;
/

You can use:
SELECT CASE
WHEN EXISTS (
SELECT 1
FROM X_TAB
WHERE dynamic_column_name = 'FISCAL_NOTE_NFE'
)
THEN 1
ELSE 0
END
FROM DUAL
It will never throw the exception as it will always return exactly one row.
You can use it like:
DECLARE
i INT := 0;
output INT;
BEGIN
FOR k IN 1 .. 100 LOOP
DBMS_OUTPUT.PUT_LINE( 'c column -->'||k );
EXECUTE IMMEDIATE 'SELECT CASE WHEN EXISTS(SELECT 1 FROM X_TAB WHERE c'||k||' = ''FISCAL_NOTE_NFE'') THEN 1 ELSE 0 END FROM DUAL'
INTO output;
IF output = 1 THEN
DBMS_OUTPUT.PUT_LINE( 'c column'||k );
i := k;
EXIT;
END IF;
END LOOP;
-- Do something with i
END;
/

You can also use
select count(1) from X_TAB

Related

Exception in a loop

BEGIN
for i in 1..5 loop
select n.id_naprawy
INTO r_identyfikator_naprawy
from naprawy n
where n.id_naprawy = 1;
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('Nieprawidlowa lista napraw ');
RETURN;
END LOOP;
END;
WHEN - wrong syntax, When I add loop I got an error. What should I do?
You need altogether BEGIN..EXCEPTION..END as follows:
BEGIN
for i in 1..5 loop
BEGIN -- this
select n.id_naprawy
INTO r_identyfikator_naprawy
from naprawy n
where n.id_naprawy = 1;
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('Nieprawidlowa lista napraw ');
RETURN;
END; -- this
END LOOP;
END;

multiple IF inside cursor loop

after this question, I'm unable to evaluate with different IFs statements inside one single loop, my execution ends with ORA-01403: no data found
What I have:
Declaration:
CREATE OR REPLACE PACKAGE MYSCHEMA.MYPKG AS
FUNCTION MYFUNCTION ( description OUT VARCHAR2 ) RETURN INTEGER;
END MYPKG;
Body:
CREATE OR REPLACE PACKAGE BODY MYSCHEMA.MYPKG AS
FUNCTION MYFUNCTION ( description OUT VARCHAR2 ) RETURN INTEGER AS
CURSOR CUR_MYDATA IS
SELECT
o.name,
o.last_name,
o.id,
o.socnum
FROM
origin o
WHERE
1=1
AND o.name like upper ('a%');
TYPE t_name IS TABLE OF origin.name%TYPE;
TYPE t_lastname IS TABLE OF origin.last_name%TYPE;
TYPE t_id IS TABLE OF origin.id%TYPE;
TYPE t_socnum IS TABLE OF origin.socnum%TYPE;
l_name t_name;
l_lastname t_lastname;
l_id t_id;
l_socnum t_socnum;
retcode INTEGER := 0;
BEGIN
description := 'OK';
OPEN CUR_MYDATA;
LOOP
FETCH CUR_MYDATA BULK COLLECT INTO l_name,l_lastname,l_id,l_socnum;
EXIT WHEN l_name.count = 0;
for name in l_name.first .. l_name.last loop
IF l_socnum(name) IS NULL THEN
(select oo.socnum from other_origin where oo.id=l_id(name))
END IF;
IF length(l_lastname(name)) < 2 THEN
l_lastname(name) := 'default lastname';
END IF;
end loop;
forall i IN l_name.first .. l_name.last
INSERT INTO destiny (
d_name,
d_lastname,
d_id,
d_socnum)
VALUES (
l_name(i),
l_lastname(i),
l_id(i),
l_socnum(i));
END LOOP;
COMMIT;
RETURN retcode;
EXCEPTION
WHEN OTHERS THEN
description := SQLERRM;
retcode := SQLCODE;
CLOSE CUR_MYDATA;
RETURN retcode;
END MYFUNCTION;
END MYPKG;
But I got ORA-01403: no data found
I also tried:
for name in l_name.first .. l_name.last loop
IF l_socnum(name) IS NULL THEN
(select oo.socnum
into l_socnum(name)
from other_origin where oo.id=l_id(name))
for ln in l_name.first .. l_name.last loop
IF length(l_lastname(ln)) < 2 THEN
l_lastname(ln) := 'default lastname';
END IF;
end loop;
END IF;
end loop;
But error is the same.
So, what do you think that I'm missing when I loop more than once through my cursor evaluating differents columns?

Can't Solve ora-06550 pls-00103 ERROR in Qyery

I wrote the following query to Update Table EMPSHIFT VALUES From SCHEDULEEMPLOYEES
Table but get the following Error ora-06550 pls-00103 and can't solve it
so what is the problem
DECLARE
day_date DATE:=TO_DATE('01/04/2017','DD/MM/YYYY');
BEGIN
LOOP
FOR employees IN (SELECT EmpID FROM EMPSHIFT)
LOOP
EXECUTE IMMEDIATE
' UPDATE EMPSHIFT SET EMPSHIFT."'||TO_CHAR(day_date)||'" =
(
SELECT SCHEDULEEMPLOYEES.SCHEDULEID ||'-'|| SCHEDULEEMPLOYEES.SHIFTS
FROM SCHEDULEEMPLOYEES INNER JOIN EMPSHIFT ON SCHEDULEEMPLOYEES.EMPLOYEEID = EMPSHIFT.EMPLOYEEID
WHERE SCHEDULEEMPLOYEES.DAYDATE = '||TO_CHAR(day_date)||' and EMPSHIFT.EMPLOYEEID = ' || employees.EmpID ||'
)
WHERE EMPSHIFT.EMPLOYEEID =' ||employees.EmpID ||';';
day_date = day_date + 1;
EXIT
WHEN day_date >TO_DATE('30/04/2017','DD/MM/YYYY');
END LOOP;
END LOOP;
END;
1) As others mentioned,"day_date = day_date + 1;" has missing the correct assignment operator ":=".
2) The "EXECUTE..." part is not required here. Why are You using it?
3) What is your goal? The current structure looks "weird". The first loop statement has no control of the flow, only the inner one has, but its loop iterations is only based on the employees count, not the dates.
4) Is the update statement correct? I mean the "set empshift.<..>. I doubt, he has an attribute named "01/04/2017".
Created an example,:
declare
l_day_date date:=to_date('01/04/2017','DD/MM/YYYY');
l_res varchar2(400);
begin
loop
for l_emp in (select emp_id from empshift_test_v)
loop
dbms_output.put_line('the emp_id is :'||l_emp.emp_id);
--update empshift_test_v etv
--set etv.empshift_code/*<correct_att_name>*/ = (
select
nvl((select
sct.sch_id ||'-'|| sct.shifts shift_code
from
SCHEDULEEMPLOYEES_TEST_V sct,
empshift_test_v etv1
where
sct.day_date = l_day_date and
sct.emp_id = etv1.emp_id and
etv1.emp_id = l_emp.emp_id),'no_info')
into
l_res
from
empshift_test_v etv
where
etv.emp_id = l_emp.emp_id;
dbms_output.put_line('day_date is :'||to_char(l_day_date,'DD/MM/YYYY'));
dbms_output.put_line('l_res is :'||l_res);
end loop;
l_day_date := l_day_date + 1;
exit when l_day_date >to_date('30/04/2017','DD/MM/YYYY');
end loop;
end;
WHERE views "EMPSHIFT_TEST_V" and "SCHEDULEEMPLOYEES_TEST_V" has info like:
enter image description here
Hope it helps.
UPDATE:
Modified it according to you data.
declare
l_day_date date:=to_date('01/04/2017','DD/MM/YYYY');
l_res number;
l_stmt varchar2(4000);
begin
loop
for l_emp in (select emp_id from empshift_test)
loop
dbms_output.put_line('the emp_id is :'||l_emp.emp_id);
begin
select
sct.shift
into
l_res
from
SCHEDULEEMPLOYEES_TEST sct,
empshift_test etv
where
sct.daydate = l_day_date and
sct.emp_id = etv.emp_id and
etv.emp_id = l_emp.emp_id;
exception
when NO_DATA_FOUND then
l_res := 0;
end;
dbms_output.put_line('day_date is :'||to_char(l_day_date,'DD/MM/YYYY'));
dbms_output.put_line('l_res is :'||l_res);
if l_res > 0 then
l_stmt := 'update empshift_test emp
set emp."'||to_char(l_day_date,'DD/MM/YYYY')||'" = '||l_res||'
where emp.emp_id = '||l_emp.emp_id||';';
dbms_output.put_line('l_stmt is :'||l_stmt);
execute immediate l_stmt;
end if;
end loop;
l_day_date := l_day_date + 1;
exit when l_day_date >to_date('30/04/2017','DD/MM/YYYY');
end loop;
end;
But there is a catch: if you run the DML statement manually - it works, but with execute immediate - it throws error ora-00933. He cant read the number column for some reason.
Another good stack question to solve:)
So the plan is:
1) Change the table structure; or
2) Solve the problem, when calling a attribute, named as number (with symbols like "/") using execute immediate.

Oracle PL/SQL - how do I run the same block of code for ALL exceptions?

Oracle 11g. This seems like it should be stupidly obvious, but I haven't seen an example. I have 2 exceptions which each need to write slightly different log messages, and then they should do the same UPDATE and CONTINUE.
Is there any way to structure the exception so I only need to type the UPDATE and CONTINUE statements once, while keeping the different logging?
FOR my_rec IN my_cursor
LOOP
BEGIN
...do some stuff
EXCEPTION
WHEN NO_DATA_FOUND THEN
log_detail.new('Skipping record - ID not found');
UPDATE my_table
SET operation_result = 'Failed'
WHERE my_id = my_rec.some_id;
CONTINUE;
WHEN OTHERS THEN
log_detail.new('Skipping record - unknown error');
UPDATE my_table
SET operation_result = 'Failed'
WHERE my_id = my_rec.some_id;
CONTINUE;
END;
END LOOP;
Did you try:
FOR my_rec IN my_cursor
LOOP
BEGIN
...do some stuff
EXCEPTION
WHEN OTHERS THEN
if sqlcode=-1403 then
log_detail.new('Skipping record - ID not found');
else
log_detail.new('Skipping record - unknown error');
end if;
UPDATE my_table
SET operation_result = 'Failed'
WHERE my_id = my_rec.some_id;
CONTINUE;
END;
END LOOP;
You could try:
DECLARE
vError VARCHAR2(1);
vMessage VARCHAR2(100);
BEGIN
FOR my_rec IN my_cursor LOOP
vError := 'N';
BEGIN
...do some stuff
EXCEPTION
WHEN NO_DATA_FOUND THEN
vError := 'S';
vMessage := 'Skipping record - ID not found';
WHEN OTHERS THEN
vError := 'S';
vMessage := 'Skipping record - unknown error';
END;
IF vError = 'S' THEN
log_detail.new(vMessage);
UPDATE my_table
SET operation_result = 'Failed'
WHERE my_id = my_rec.some_id;
CONTINUE;
END IF;
END LOOP;
END;

ORA-01775: looping chain of synonyms but there are no synonyms

Can't figure out why I'm getting 'SQL Statement ignored' and 'ORA-01775: looping chain of synonyms' on line 52 of this stored procedure. Got any ideas?
CREATE OR REPLACE PACKAGE PURGE_LOG_BY_EVENT_DAYS AS
TYPE dual_cursorType IS REF CURSOR RETURN dual%ROWTYPE;
PROCEDURE log_master_by_event_days (event_id NUMBER, purge_recs_older_than NUMBER, result_cursor OUT dual_cursorType);
END PURGE_LOG_BY_EVENT_DAYS;
/
CREATE OR REPLACE PACKAGE BODY PURGE_LOG_BY_EVENT_DAYS
AS
err_msg VARCHAR2(4000);
PROCEDURE log_master_by_event_days (event_id NUMBER, purge_recs_older_than NUMBER, result_cursor OUT dual_cursorType)
IS
TYPE type_rowid IS TABLE OF ROWID INDEX BY BINARY_INTEGER;
TYPE type_ref_cur IS REF CURSOR;
l_rid type_rowid;
c1 type_ref_cur;
l_sql_stmt VARCHAR2(4000);
proc_start_time DATE := sysdate;
purge_date DATE;
l_bulk_collect_limit NUMBER := 1000;
retry NUMBER := 5;
retry_count NUMBER := 0;
loop_count NUMBER := 0;
err_code VARCHAR2(10);
BEGIN
purge_date := to_date(sysdate - purge_recs_older_than);
l_sql_stmt := '';
l_sql_stmt := l_sql_stmt ||' SELECT rowid FROM LOG_MASTER ';
l_sql_stmt := l_sql_stmt ||' WHERE last_changed_date < :purge_date';
l_sql_stmt := l_sql_stmt ||' AND event_id = :event_id';
-- The following while loop
-- executes the purge code
-- 'retry' number of times in case of ORA-01555
WHILE retry > 0 LOOP
BEGIN
-- START of purge code
OPEN c1 FOR l_sql_stmt USING purge_date, event_id;
LOOP
FETCH c1 BULK COLLECT into l_rid LIMIT l_bulk_collect_limit;
FORALL i IN 1..l_rid.COUNT
DELETE from log_master
WHERE rowid = l_rid(i);
COMMIT;
loop_count := loop_count + 1;
EXIT WHEN c1%NOTFOUND;
END LOOP;
CLOSE c1;
-- End of purge code
-- if processing reached this point
-- Process completed successfuly, set retry = 0 to exit loop
retry := 0;
EXCEPTION
WHEN OTHERS THEN
-- ====================================
-- Get error msg
-- ====================================
ROLLBACK;
err_code := sqlcode;
dbms_output.put_line(err_code);
-- ====================================
-- Check if it is 01555
-- if so retry, else exit loop
-- ====================================
retry := retry - 1;
if err_code = '-1555' and retry > 0 THEN
CLOSE c1;
retry_count := retry_count + 1;
else
err_msg := sqlerrm;
exit;
end if;
END;
END LOOP;
IF err_msg IS NULL THEN
open result_cursor for select '1 - PURGE_LOG_BY_EVENT_DAYS ran successfully (event_id : '||event_id||', loop_count : '||loop_count||', bulk_limit : '||l_bulk_collect_limit||', retries : '||retry_count||') ' from dual;
ELSE
open result_cursor for select '2 - PURGE_LOG_BY_EVENT_DAYS After (event_id : '||event_id||', loop_count : '||loop_count||', bulk_limit : '||l_bulk_collect_limit||', retries : '||retry_count||') with Error: ' || err_msg from dual;
END IF;
END log_master_by_event_days;
END PURGE_LOG_BY_EVENT_DAYS;
I have no idea why you're getting the synonym error. But that's a lot of code for something that should be a single DELETE statement. I assume you've changed it to commit-every-n to avoid rollback errors. It would be nice if you could get your DBA to increase the undo space so you can actually do the work you need to do. Failing that, I think you can still make it much simpler:
LOOP
DELETE FROM log_master
WHERE last_changed_date < :purge_date
AND event_id = :event_id
AND rownum <= :batch_delete_limit
USING purge_date, event_id, l_bulk_collect_limit;
EXIT WHEN SQL%NOTFOUND;
END LOOP;
And you can throw your retry logic around that if you want.
Apologies if I've missed some subtlety that makes this different from what you're doing.
SELECT table_owner, table_name, db_link
FROM dba_synonyms
WHERE owner = 'PUBLIC' and db_link is not null
returns 0 rows
as far as i know, there are no synonyms.......

Resources