Print first 100 values using cursor in PL/SQL - sql

I am trying to print the first 100 values for a field using cursor.I get an ORA-06550 error here though.Could someone tell me what is that I am missing .
Declare
BG_TOTAL number;
cursor c1 is
select BG_ID
from <tablename>;
Type BG_TAB_TYPE is table of c1%ROWTYPE;
BG_LIST BG_TAB_TYPE;
Begin
open c1;
FETCH c1 BULK COLLECT INTO BG_LIST;
close c1;
for i in 1..c1.count
loop
DBMS_OUTPUT.PUT_LINE(c1(i).BG_ID);
End loop;
end;

Yet another option is to use bulk collect with a limit.
This nicely separates the content, the limitation and the processing. The separation might not be an issue in your case but I have found this useful every now an then (helps me to write more modular code that's easy to test).
declare
-- data content
cursor tables_c is select * from all_tables;
type table_list_t is table of tables_c%rowtype;
v_table_list table_list_t;
begin
open tables_c;
-- limiting the data set
fetch tables_c bulk collect into v_table_list limit 8;
-- processing
for i in 1 .. v_table_list.count loop
dbms_output.put_line(v_table_list(i).table_name);
end loop;
close tables_c;
end;
/

You should loop through the nested table to which you bulk-collected records, not through the cursor. This is the corrected code:
Declare
BG_TOTAL number;
cursor c1 is
select BG_ID
from my_Tab524;
Type BG_TAB_TYPE is table of c1%ROWTYPE;
BG_LIST BG_TAB_TYPE;
Begin
open c1;
FETCH c1 BULK COLLECT INTO BG_LIST;
close c1;
for i in 1..BG_LIST.count
loop
DBMS_OUTPUT.PUT_LINE(BG_LIST(i).BG_ID);
EXIT WHEN i = 10;
End loop;
end;

Related

finding records with cursors and procedures

i dont kno whow to write a proper procedure wtih cursors. i am doing somehtings wring ?
procedure1: for given student show all titles of books he ever rented
--no such student no recordsexcep
SET SERVEROUTPUT ON
create or replace procedure showRENTS(v_idStudent int)
as
v_NameOfBook varchar2(100);
--v_count int;
no_such_id EXCEPTION;
cursor c1 is
select NameOfbook from book
where
begin
open c1;
loop
fetch c1
into v_fname,v_lname;
--select count(1) into v_count from Student where idStduent =v_id ;
--if
--v_count = 0;
--then raise no_such_id;
--end if;
exit when c1%notfounf
end loop;
close c1;
end;
/
I can't see images, but - procedure you posted can be rewritten to
CREATE OR REPLACE PROCEDURE showrents (v_idstudent IN INT)
AS
BEGIN
FOR c1 IN (SELECT nameofbook FROM book)
LOOP
DBMS_OUTPUT.put_line (c1.nameofbook);
END LOOP;
END;
/
I'd suggest you to use cursor FOR loop - it is simpler to write & maintain as Oracle does most of job for you (you don't have to declare cursor variable, open the cursor, fetch from it, take care about exiting the loop, closing the cursor).
I'm not sure what its parameter has to do with it but I left it; I guess you'll add some code later.
I hope it'll get you started.
For issues like this just follow your ERD. So here your given a student is and asked for the book rented. Follow the path: Student -> Process -> Copies -> Book. It actually becomes a fairly easy query.
create or replace procedure showrents(v_idStudent int)
as
no_such_id EXCEPTION;
v_student_ok interger :=0;
cursor c_student_books is
select nameofbook
from student s
join process p on (p.idstudent = s.idstudent)
join copies c on (c.idcopies = p.idcopies)
join books b on (b.idbook = b.idbook)
where s.idstudent = v_idStudent;
begin
select count(*)
into v_student_ok
from student
where idstudent = v_idstudent
and rownum <= 1;
if v_student_ok = 0
then
raise no_such_id;
end if;
for rented in c_student_books
loop
dbms_output.put_line( rented.nameofBook);
end ;
end showrents; ```

Novice to DB - Oracle

I'm pretty new to Oracle and Database.
I'm trying to write a stored procedure with cursors. How do I write a select statement inside the cursor loop, and how do I loop through the result set that I get from the select inside that cursor loop?
For example:
Open Curs1;
Exit When Curs1%NotFound;
Loop
Select column1,column2 from table -- Returns multiple records. How to loop through this record set and perform CRUD operations.
End loop;
Close Curs1;
Use a FOR-loop cursor - they are faster and simpler than the open/fetch/close syntax.
begin
for results1 in
(
select ...
) loop
--Do something here
for results2 in
(
select ...
where some_table.some_column = results1.some_column
) loop
--Do something here
end loop;
end loop;
end;
/
Although this literally answers the question, you generally do not want to have loops inside loops like this. If possible, it would be better to combine the two SQL statements with a join and then loop through the results.
Try to use the following example that fetches rows one at a time from the cursor variable emp_cv into the user-defined record emp_rec:
declare
TYPE YourType IS ref cursor return YourTable%rowtype;
tab_cv YourType;
tab_rec YourTable%rowtype;
begin
loop
fetch tab_cv into emp_rec;
exit when tab_cv%notfound;
...
end loop;
end;
The BULK COLLECT clause lets you fetch entire columns from the result set, or the entire result set at once. The following example, retrieves columns from a cursor into a collection:
declare
type NameList IS table of emp.ename%type;
names NameList;
cursor c1 is select ename from emp where job = 'CLERK';
begin
open c1;
fetch c1 bulk collect into names;
...
close c1;
end;
The following example uses the LIMIT clause. With each iteration of the loop, the FETCH statement fetches 100 rows (or less) into index-by table acct_ids. The previous values are overwritten.
declare
type NumList is table of number index by binary_integer;
cursor c1 is select acct_id from accounts;
acct_ids NumList;
rows natural := 100; -- set limit
begin
open c1;
loop
/* The following statement fetches 100 rows (or less). */
fetch c1 bulk collect into acct_ids limit rows;
exit when c1%notfound;
...
end loop;
close c1;
end;
You need to declare the CURSOR and FETCH the records in the loop.
DECLARE
CURSOR curs1
IS
SELECT column1,
column2
FROM yourtable;
v_column1 yourtable.column1%TYPE;
v_column2 yourtable.column2%TYPE;
BEGIN
OPEN curs1;
LOOP
FETCH curs1
INTO v_column1,
v_column2;
EXIT
WHEN curs1%NOTFOUND;
INSERT INTO yourtable2(col1)VALUES( '000'||v_column1 );
-- A sample DML operation.
--Do other operations on individual records here.
END LOOP;
CLOSE curs1;
END;

How to execute results of dbms_output.put_line

There is a table contains this kind of data: select to_char(sysdate,'day') from dual in a column. I want to get results of the every query that the table keeps.
My result set should be the result of select to_char(sysdate,'day') from dual query. So in this case it is a tuesday.
SO_SQL_BODY is Varchar2.
I wrote this code but it returns only table data.
CREATE or replace PROCEDURE a_proc
AS
CURSOR var_cur IS
select SO_SQL_BODY FROM SO_SUB_VARS group by SO_SQL_BODY;
var_t var_cur%ROWTYPE;
TYPE var_ntt IS TABLE OF var_t%TYPE;
var_names var_ntt;
BEGIN
OPEN var_cur;
FETCH var_cur BULK COLLECT INTO var_names;
CLOSE var_cur;
FOR indx IN 1..var_names.COUNT LOOP
DBMS_OUTPUT.PUT_LINE(var_names(indx).SO_SQL_BODY);
END LOOP;
END a_proc;
DECLARE
res varchar2(4000);
sql_str varchar2(1000);
BEGIN
FOR r IN
(select SO_SQL_BODY FROM SO_SUB_VARS WHERE SO_SQL_BODY IS NOT NULL
)
LOOP
sql_str := r.SO_SQL_BODY;
EXECUTE immediate sql_str INTO res;
dbms_output.put_line(sql_str);
dbms_output.put_line('***********************');
dbms_output.put_line(res);
dbms_output.put_line('***********************');
END LOOP;
END;
/
Try this - iterate to not null records - execute them and print the result.This script works supposing the fact that SO_SQL_BODY contains a query which projects only one column.Also if the projection is with more than two columns then try to use a refcursor and dbms_sql package
İf var_names(indx).SO_SQL_BODY output is a runnable sql text;
CREATE or replace PROCEDURE a_proc
AS
CURSOR var_cur IS
select SO_SQL_BODY FROM SO_SUB_VARS group by SO_SQL_BODY;
var_t var_cur%ROWTYPE;
TYPE var_ntt IS TABLE OF var_t%TYPE;
var_names var_ntt;
BEGIN
OPEN var_cur;
FETCH var_cur BULK COLLECT INTO var_names;
CLOSE var_cur;
FOR indx IN 1..var_names.COUNT LOOP
DBMS_OUTPUT.PUT_LINE(var_names(indx).SO_SQL_BODY);
EXECUTE IMMEDIATE var_names(indx).SO_SQL_BODY;
END LOOP;
END a_proc;
You don't need a full cursor for this example. An implicit one would make it a lot shorter.
create or replace procedure a_proc is
lReturnValue varchar2(250);
begin
for q in (select so_sql_body from so_sub_vars group by so_sql_body)
loop
execute immediate q.so_sql_body into lReturnValue;
dbms_output.put_line(lReturnValue);
end loop;
end a_proc;
You should add an exception handler that will care for cases where there is a bad SQL query in your table. Also note that executing querys saved in a database table is your entry point to SQL injection.

Why does bulk collect speed up the fetching after opening the cursor?

SET SERVEROUTPUT ON
DECLARE
TYPE t_bulk_collect_test_tab IS TABLE OF bulk_collect_test%ROWTYPE;
CURSOR C1 IS SELECT * FROM bulk_collect_test;
l_tab t_bulk_collect_test_tab := t_bulk_collect_test_tab();
l_start NUMBER;
BEGIN
OPEN C1;
FETCH C1 BULK COLLECT INTO t_bulk_collect_test_tab;
CLOSE C1;
END;
The question is when we open the cursor all the data are taken from database to plsql memory. Before FETCH operation the data is present in
PLSQL memory so there is no question on context switch. Is there any use of this kind of fetch operation?
when you bulk collect a cursor you take the data from DB to an array with one request to db but if you fetch each record in a loop your code send N request to database for fetch records to plsql so it has better performance.
if you have a huge result set you should use 'limit NUMBER_OF_RECORDS' after bulk collect to limit number of records which you want load from DB to pl/sql "see line 9 of following code";
opening a cursor does not load any data to memory it just create a pointer to first record of result set.
SET SERVEROUTPUT ON
DECLARE
TYPE t_bulk_collect_test_tab IS TABLE OF bulk_collect_test%ROWTYPE;
CURSOR C1 IS SELECT * FROM bulk_collect_test;
l_tab t_bulk_collect_test_tab := t_bulk_collect_test_tab();
l_start NUMBER;
BEGIN
OPEN C1;
FETCH C1 BULK COLLECT INTO t_bulk_collect_test_tab limit 500;
CLOSE C1;
END;

Oracle pl/sql reference(return?) cursor/declared cursor

Is there a way to do something like this? Output a cursor's fetched data into a refcursor without stuffing it into a table first?
create or replace procedure someprocedure
(
rc1 in out adv_refcur_pkg.rc) -- this is defined below
as
v_class_year varchar(10);
cursor c1
is
select distinct e.pref_class_year
from entity e
where e.pref_class_year between i_start_class and i_end_class;
begin
open c1;
loop
fetch c1 into v_class_year;
EXIT WHEN c1%NOTFOUND;
end loop;
close c1;
open rc1 for select v_class_year from dual;
end;
here is the refcursor's declaration
CREATE OR REPLACE PACKAGE ADVANCE.adv_refcur_pkg
AS
TYPE RC IS REF CURSOR;
END adv_refcur_pkg;
According with this example, yes, it's possible:
https://forums.oracle.com/thread/696634
Why go to the trouble of doing that when you can simply pass the cursor itself?
create or replace procedure someprocedure
(
rc1 in out adv_refcur_pkg.rc) -- this is defined below
as
begin
open rc1 for
select distinct e.pref_class_year
from entity e
where e.pref_class_year between i_start_class and i_end_class;
end;
When you call "someprocedure", you have an open cursor you can then fetch from:
BEGIN
...
someprocedure(TheCursor);
LOOP
fetch TheCursor into v_class_year;
exit when TheCursor%NOTFOUND;
...
END LOOP;
CLOSE TheCursor;
...
END;