Cursor of Oracle with Duplicate of final Record - oracle

Why am getting duplicate records ? pls correct me.Thanks in Advance.
declare
clazzes_rec clazzes%rowtype;
cursor clazzes_cur is select * from clazzes;
begin
if clazzes_cur%isopen then
dbms_output.put_line('Cursor is not open,trying to Open.... ... .. .');
end if;
open clazzes_cur;
dbms_output.put_line('Cursor opened :');
loop
fetch clazzes_cur into clazzes_rec;
dbms_output.put_line('id:'||clazzes_rec.id||':name:'||clazzes_rec.name);
exit when clazzes_cur%notfound;
end loop;
close clazzes_cur;
end;
Ouput :
Cursor opened :
id:1:name:leo1
id:2:name:leo2
id:3:name:leo3
id:4:name:leo4
id:4:name:leo4
PL/SQL procedure successfully completed

Just swap the lines:
loop
fetch clazzes_cur into clazzes_rec;
exit when clazzes_cur%notfound;
dbms_output.put_line('id:'||clazzes_rec.id||':name:'||clazzes_rec.name);
end loop;
When you have fetched the last record and trying to fetch the next clazzes_cur%notfound becomes true but before it has a chance to exit from loop you are outputting the last record once again.

Related

how do I use if condition in cursor because our professor don't allow us use where clause in the select statement

Our question is showing all the countries that have names that are exactly 5 letter long. This is the cursor code and I want add if condition into it.
declare
cursor cursor_full is select * from country_cont;
begin
for counter in cursor_full
loop
dbms_output.put_line(counter.country|| ' ' || counter.continent);
end loop;
end;
However my professor said that you can't using where clause within the select statement and you should display all the countries and continent.
so i tried this code:
declare
country varchar(50);
cursor cursor_full is select * from country_cont;
begin
if length(country)=5 then
for counter in cursor_full
loop
dbms_output.put_line(counter.country|| ' ' || counter.continent);
end loop;
end if;
end;
the script output show that PL/SQL procedure successfully completed but nothing return in DBMS output
Hope someone can help me, I spent whole night to think about it,please!
Variable country doesn't contain any value, it is null so if condition is never true and loop is never executed. Sample data would help; meanwhile, see if this helps.
begin
for cur_r in (select * from country_cont) loop
if length(cur_r.country) > 5 then
dbms_output.put_line(cur_r.country|| ' ' || cur_r.continent);
end loop;
end;
Don't forget to set serveroutput on.

PL/SQL -If exists in Table type of varchar2 not working

I am using a huge table which loops inside a cursor so i thought rather than querying on each iteration, put the particular data in a Table type and then check data exists inside the loop.
declare
type type_product_list is table of varchar(6);
product_list type_product_list;
begin
SELECT distinct(PRODUCT_NUMBER)
BULK COLLECT INTO product_list
FROM WEB_PRODUCTS web WHERE some conditions;
FOR i IN 1..product_list.COUNT LOOP
DBMS_OUTPUT.PUT_LINE(product_list(i)); -- This line printing properly.
END LOOP;
IF product_list.EXISTS('00029') THEN -- This condition always fails
DBMS_OUTPUT.PUT_LINE('Found');
ELSE
DBMS_OUTPUT.PUT_LINE('Not Found');
END IF;
end;
Output
00029
00030
00031
00032
..... other data
NOT FOUND
Please help, how can I get the IF block executed.
*Update
Main purpose of this problem is to call a function inside the IF block, and if block itself will be inside a cursor loop which gives dynamic product id in each iteration, i.e. if the product id exists then call that function.
begin
SELECT distinct(PRODUCT_NUMBER)
BULK COLLECT INTO product_list
FROM WEB_PRODUCTS web WHERE some conditions;
OPEN cur_cms_scriptdtl();
LOOP
FETCH cur_cms_scriptdtl INTO productId, productName;
EXIT WHEN cur_cms_scriptdtl%notfound;
IF product_list.EXISTS(productId) THEN
-- Function call
END IF;
END LOOP;
CLOSE cur_cms_scriptdtl;
After some digging and help from Oracle docs, I was able to get it without FOR LOOP.
The helping angel here is : member of
BEGIN
SELECT distinct(PRODUCT_NUMBER)
BULK COLLECT INTO product_list
FROM WEB_PRODUCTS web WHERE some conditions;
OPEN cur_cms_scriptdtl();
LOOP
FETCH cur_cms_scriptdtl INTO productId, productName;
EXIT WHEN cur_cms_scriptdtl%notfound;
IF productId member of product_list THEN
-- Function call
END IF;
END LOOP;
CLOSE cur_cms_scriptdtl;
In collections, exists method receives as parameter an index, not a value.
IF product_list(i) = '00029' THEN
Try this:
DECLARE
type type_product_list is table of varchar(6);
product_list type_product_list;
vFound BOOLEAN := false;
BEGIN
FOR i IN 1..product_list.COUNT LOOP
dbms_output.put_line(product_list(i));
IF product_list(i) = '00029' THEN
vFound := true;
exit;
END IF;
END LOOP;
IF vFound THEN
dbms_output.put_line('Found');
ELSE
dbms_output.put_line('Not Found');
END IF;
END LOOP;

Oracle Function that return table of number problems and performance

I have (sometimes) a memory block in my oracle database that turn crasy... a lot of session sundenless block each other and the probleme is in a function that return a table of number and is use in another procedure.
Edit : Sessions is 'blocked' with Read By Other Session Wait Event
First, my table of number :
CREATE OR REPLACE TYPE liste_lots as TABLE OF number(10)
and in large the function who populate the table :
function get_ot_idem_cursor( .. ) return liste_lots is
res_type liste_lots;
p_restriction_level number;
cursor curs_lvl_1 is select [...] ;
row_lvl_1 curs_lvl_1%rowtype;
cursor curs_lvl_0 is select [...] ;
row_lvl_0 curs_lvl_0%rowtype;
begin
res_type := liste_lots();
p_restriction_level := get_edi_line_restriction(p_edi_line);
if p_restriction_level = 1 then
open curs_lvl_1;
loop
fetch curs_lvl_1 into row_lvl_1;
exit when curs_lvl_1%notfound;
begin
res_type.extend;
res_type(res_type.last) := row_lvl_1.lot_id;
exception
when others then
dbms_output.put_line('problème get_ot_idem_cursor ');
dbms_output.put_line(sqlerrm);
close curs_lvl_1;
end;
end loop;
close curs_lvl_1;
else
open curs_lvl_0;
loop
fetch curs_lvl_0 into row_lvl_0;
exit when curs_lvl_0%notfound;
begin
res_type.extend;
res_type(res_type.last) := row_lvl_0.lot_id;
exception
when others then
dbms_output.put_line('problème get_ot_idem_cursor ');
dbms_output.put_line(sqlerrm);
close curs_lvl_0;
end;
end loop;
close curs_lvl_0;
end if;
return res_type;
exception
when others then
if curs_lvl_0%isopen then
close curs_lvl_0;
end if;
if curs_lvl_1%isopen then
close curs_lvl_1;
end if;
end;
and is used on another part like that :
liste_ots := get_ot_idem_cursor(v_lot, v_sr_ligne_lot.id );
select min(l.lot_id) into result
from lot l
where l.des_tiers_id = p_pf_tiers_id
and l.lot_nature = 'POS'
and l.exp_tiers_id = v_sr_ligne_lot.ramasse_tiers_id
and ot_id in ((select * from TABLE(liste_ots)))
and l.lot_datheurcharg > sysdate - 3;
When the db become crasy (session block, very slow) this is the part of the code who is pointed :
select * from TABLE(liste_ots)
the problem is not all the time, then if you have any idea or advise...
thanks in advance (sorry for my bad english)
Use a bulk collect instead of a plain loop (fetching records one by one) as there is no additional logic done in the loop. In general, always avoid switching a context (SQL to/from PL/SQL)
open curs_lvl_1;
fetch curs_lvl_1 bulk collect into res_type;
close curs_lvl_1;

Multiple line output in pl/sql

I have a PL/SQL file that has a loop structure.
The script is as follows.
SET SERVEROUTPUT ON
declare
c_id employee.id%type;
c_name employee.name%type;
c_address employee.address%type;
CURSOR c_employee is
SELECT id, name, address from employee;
begin
open c_employee;
LOOP
FETCH c_employee into c_id, c_name, c_address;
EXIT when c_employee%notfound;
dbms_output.put_line(c_id||' '||c_name||' '||c_address);
END LOOP;
close c_employee;
end;
/
When I run this from SQLPlus I get only the details of the first row but not the rest. What am I doing wrong? How to get all the outputs for the loop.
Try to convert your code to use a for loop instead of the open statement, like so -
for r_employee in c_employee
LOOP
dbms_output.put_line(r_employee.c_id||' '||r_employee.c_name||' '||r_employee.c_address);
END LOOP;
Where r_employee is a variable of employee%type.
The way you currently wrote it does not iterate through the cursor, and this is why only the first row is presented.
Even though your code looks correct, it should iterate through all the
row not just one. Try to use below snippet and run it in SQL plus if
still single row then there may be some other issue.
SET SERVEROUTPUT ON
DECLARE
BEGIN
FOR I IN
(SELECT id, name, address FROM employee
)
LOOP
dbms_output.put_line(I.ID||' '||I.name||' '||I.address);
END LOOP;
END;
/

PL/SQL - Pre actions if cursor is found

I have a simple cursor like this:
CURSOR emp_cur
IS
SELECT *
FROM employee
WHERE age > 20;
In my procedure, I want to do some pre-actions only if there are employee in cursor. After that pre-action, I process all rows.
I need this because only if exists employee in that cursor i need to cleanup some tables, otherwise i should "RETURN".
so the code could be:
OPEN emp_cur;
/* Here i need to do pre-action only if emp_cur has rows*/
IF /* has rows*/
THEN
/* do some actions*/
END IF;
LOOP
FETCH emp_cur INTO emp_rec;
EXIT WHEN emp_cur%NOTFOUND;
END LOOP;
CLOSE emp_cur;
For now, i have a "dirty" solution where i open cursor:
First to check if there are rows
Do pre-action and close
Open/fetch again to process rows, and close again
First to check if there are rows
You cannot know about the rows until you FETCH.
From documentation link ,
After a cursor or cursor variable is opened but before the first
fetch, %FOUND returns NULL. After any fetches, it returns TRUE if the
last fetch returned a row, or FALSE if the last fetch did not return a
row.
Once you have fetched the rows, then before processing the rows, you could use %FOUND.
For example,
OPEN c1;
LOOP
FETCH c1 INTO my_ename, my_salary;
IF c1%FOUND THEN -- fetch succeeded
-- Do something
ELSE -- fetch failed, so exit loop
EXIT;
END IF;
END LOOP;
Thinking a little i've wrote this procedure that avoid an IF inside the loop. I know, is a little "strange" but is the only thing i've think works:
OPEN emp_cur;
FECTH emp_cur INTO emp_rec;
IF emp_cur%FOUND
THEN
-- pre actions
END IF;
LOOP
EXIT WHEN emp_cur%NOTFOUND;
-- do something in the loop
FECTH emp_cur INTO emp_rec; -- First fetch was done before the if
END LOOP;
CLOSE emp_cur;

Resources