RDBMS_Unit5
RDBMS_Unit5
Cursors
Unit 5
Cursor
A cursor is a temporary work area created in the system memory
when a SQL statement is executed.
A cursor contains information on a select statement and the rows
of data accessed by it.
This temporary work area is used to store the data retrieved from
the database, and manipulate this data.
A cursor can hold more than one row, but can process only one
row at a time.
The set of rows the cursor holds is called the active set.
1
10/7/2019
Types of Cursors
There are two types of cursors −
Implicit cursors
Explicit cursors
Implicit Cursors
2
10/7/2019
3
10/7/2019
The following program will update the table and increase the salary of
each customer by 500 and use the SQL%ROWCOUNT attribute to
determine the number of rows affected −
DECLARE
total_rows number(2);
BEGIN
UPDATE customers SET salary = salary + 500;
IF sql%notfound THEN
dbms_output.put_line('no customers selected');
ELSIF sql%found THEN
total_rows := sql%rowcount;
dbms_output.put_line( total_rows || ' customers selected ');
END IF;
END;
Prepared By Shimi Biju 7
If you check the records in customers table, you will find that the rows
have been updated −
Select * from customers;
4
10/7/2019
Explicit Cursors
5
10/7/2019
Declaring the cursor defines the cursor with a name and the
associated SELECT statement. For example −
CURSOR c_customers IS
SELECT id, name, address FROM customers;
Opening the cursor allocates the memory for the cursor and
makes it ready for fetching the rows returned by the SQL
statement into it.
For example, we will open the above defined cursor as follows −
OPEN c_customers;
6
10/7/2019
CLOSE c_customers;
7
10/7/2019
When a cursor is opened, the first row becomes the current row.
When the data is fetched it is copied to the record or variables and
the logical pointer moves to the next row and it becomes the
current row.
On every fetch statement, the pointer moves to the next row.
If you want to fetch after the last row, the program will throw an
error.
When there is more than one row in a cursor we can use loops
along with explicit cursor attributes to fetch all the records.
8
10/7/2019
DECLARE
variables;
records;
create a cursor;
BEGIN
OPEN cursor;
FETCH cursor;
process the records;
CLOSE cursor;
END;
9
10/7/2019
Table records.
DECLARE
emp_rec emp_tbl%rowtype;
CURSOR emp_cur IS
SELECT * FROM customers
WHERE salary > 10;
BEGIN
OPEN emp_cur;
FETCH emp_cur INTO emp_rec;
dbms_output.put_line (emp_rec.first_name || ' ' || emp_rec.last_name);
CLOSE emp_cur;
END;
Cursor-based records.
The following example illustrates the concept of cursor-based records.
DECLARE
CURSOR customer_cur is
SELECT id, name, address
FROM customers;
customer_rec customer_cur%rowtype;
BEGIN
OPEN customer_cur;
LOOP
FETCH customer_cur into customer_rec;
EXIT WHEN customer_cur%notfound;
DBMS_OUTPUT.put_line(customer_rec.id || ' ' || customer_rec.name);
END LOOP;
END;
10
10/7/2019
11
10/7/2019
DECLARE
CURSOR emp_cur IS
SELECT first_name, last_name, salary FROM emp_tbl;
emp_rec emp_cur%rowtype;
BEGIN
FOR emp_rec in sales_cur
LOOP
dbms_output.put_line(emp_cur.first_name || ' ' |emp_cur.last_name
|| ' ' ||emp_cur.salary);
END LOOP;
END;
Prepared By Shimi Biju 23
Cursor Variables
A cursor variable is a variable that references to a cursor.
Different from implicit and explicit cursors, a cursor variable is
not tied to any specific query. Meaning that a cursor variable can
be opened for any query.
The most important benefit of a cursor variable is that it enables
passing the result of a query between PL/SQL programs.
Without a cursor variable, you have to fetch all data from a
cursor, store it in a variable e.g., a collection, and pass this
variable as an argument.
With a cursor variable, you simply pass the reference to that
cursor.
12
10/7/2019
Cursor variables are defined using a REF CURSOR type. The type is
defined in one of two ways:
13
10/7/2019
DECLARE
TYPE customer_t IS REF CURSOR;
c_customer customer_t;
14
10/7/2019
SYS_REFCURSOR
The SYS_REFCURSOR cursor variable is an Oracle-defined
weak Ref-Cursor type, which is pre-declared in the STANDARD
package.
We are free to use this Ref-Cursor type as parameters for our sub-
routines and return type for the functions without needing to
create them in a package specification, as it is already done by
Oracle for us.
As SYS_REFCURSOR is a weakly typed Ref-Cursor, it assumes
any record structure as its return type during its run time.
When we open a cursor variable created with the
SYS_REFCURSOR type, a reference is created in the SGA,
which can be then passed to another program or client
environment as a cursor variable.
Prepared By Shimi Biju 30
15
10/7/2019
DECLARE
c_cursor SYS_REFCURSOR;
l_row cursor_variable_test%ROWTYPE;
BEGIN
DBMS_OUTPUT.put_line('Weakly typed REF CURSOR using SYS_RECURSOR');
LOOP
FETCH c_cursor INTO l_row;
EXIT WHEN c_cursor%NOTFOUND;
DBMS_OUTPUT.put_line(l_row.id || ' : ' || l_row.description);
END LOOP;
CLOSE c_cursor;
END;
Prepared By Shimi Biju 31
Parameterized Cursors
The parameterized cursors are the further extension to the explicit
cursors having IN type parameters for limiting the number of
rows processed by the cursor associated SELECT statement while
opening them.
16
10/7/2019
These types of cursors do not have any return type and are
generally used in procedures, functions and anonymous blocks
which are not encapsulated within a package.
17
10/7/2019
DECLARE
l_rt_emp employees%rowtype;
CURSOR cur(ip_n_emp_id NUMBER) IS
SELECT * FROM employees WHERE
employee_id=ip_n_emp_id;
BEGIN
OPEN cur(:ip_n_emp_id);
FETCH cur INTO l_rt_emp;
dbms_output.put_line(l_rt_emp.last_name||', '||l_rt_emp.first_name);
CLOSE cur;
END;
18
10/7/2019
We can pass parameters into a cursor and use them in the query.
We can only pass values to the cursor; and cannot pass values out of the
cursor through parameters.
Optionally, we can also give a default value for the parameter, which
will take effect if no value is passed to the cursor.
19
10/7/2019
BEGIN
OPEN cur_dept;
LOOP
FETCH cur_dept INTO r_dept;
EXIT WHEN cur_dept%NOTFOUND;
DBMS_OUTPUT.PUT_LINE ('Department : ' || r_dept.deptno || ' - '|| r_dept.dname);
var_tot_salary := 0;
OPEN cur_emp (r_dept.deptno);
LOOP
FETCH cur_emp INTO var_ename, var_salary;
EXIT WHEN cur_emp%NOTFOUND;
DBMS_OUTPUT.PUT_LINE ('Name: ' ||var_ename || ' Salary:'||var_salary);
var_tot_salary := var_tot_salary + var_salary;
END LOOP;
CLOSE cur_emp;
DBMS_OUTPUT.PUT_LINE ('Total Salary for Dept: ' || var_tot_salary);
END LOOP;
CLOSE cur_dept;
END;
Prepared By Shimi Biju 39
20