Saturday, January 28, 2023

PL/SQL - Cursors

Cursors:

Oracle creates a memory area, called as context area for processing an SQL statement, which contains all information needed for processing the statement.

A cursor is a pointer to this context area. PL/SQL controls the context area through cursor. A cursor holds the rows( one or many) returned by a SQL statement. The set of rows the cursor holds is referred to as the active set.

We can name a cursor so that we can use it in a program to fetch and process the rows returned by the SQL statements, one at a time,

There are two types of cursors:

  • Implicit cursor
  • Explicit cursor
Implicit cursor:

  • Implicit cursors are automatically created by Oracle whenever an SQL statement(DML statements like INSERT, UPDATE AND DELETE) is executed. 
  • For INSERT operations, the cutsor holds the data that needs to be inserted. For UPDATE AND DELETE operations, the cursors identifies the tows that would be affected.
In PL/SQL, we can refer to the most recent implicit cursor as the SQL CURSOR, which always has the following attributes:

%FOUND : Returns true of Select into, insert, update and delete statement affected one or more rows, else it returns FALSE.

%ISOPEN : always returns false, cause Oracle closes the sql cursor automatically after executing its associated sql statement.

%NOTFOUND : The logical opposite of %FOUND.

%ROWCOUNT: Returns the number of rows affected by an INSERT, UPDATE OR DELETE or returned by a SELECT INTO statement.

Example:

IF sql%found THEN
total_rows := sql%rowcount;
dbms_output.put_line( total_rows || 'customers selected ');
END IF;

Explicit cursor:

A cursor which we can create ourselves, not a default oracle one, is called explicit cursor. 

**A cursor is the name for a structure in memory, called a private SQL area, which the server allocates at runtime for each statement.

Steps to create an Explicit cursor:
  • Declare
  • Open
  • Fetch one or more times
  • Close

Example1: retrieving 1 row using explicit cursor:

CREATE OR REPLACE PROCEDURE GET_CUSTOMER
(
c_id IN NUMBER
)
AS
c_name customer.first_name%type;
c_country customer.country%type;

--declaration of cursor
cursor c is SELECT first_name, country FROM customer WHERE customer_id = c_id;

BEGIN

open c; -- open cursor

-- fetching of data
fetch c INTO c_name, c_country;

dbms_output.put_line('Name: '|| c_name);
dbms_output.put_line('Country: '|| c_country);

Close c; --closing cursor.

EXCEPTION
WHEN no_data_found THEN
dbms_output.put_line('No such customer!');

WHEN too_many_rows THEN
dbms_output.put_line('You got more than 1 row!');
WHEN others THEN
dbms_output.put_line('Error!');
END;
/

Example2: retrieving more than 1 row using explicit cursor:

CREATE OR REPLACE PROCEDURE GET_CUSTOMER
(
c_id IN NUMBER
)
AS
c_name customer.first_name%type;
c_country customer.country%type;

--declaration of cursor
cursor c is SELECT first_name, country FROM customer WHERE customer_id = c_id;

BEGIN

open c; -- open cursor

LOOP
-- fetching of data
fetch c INTO c_name, c_country;

EXIT WHEN C%NOTFOUND;
dbms_output.put_line('Name: '|| c_name);
dbms_output.put_line('Country: '|| c_country);

END LOOP;

Close c; --closing cursor.
END;

Using Records in cursor:

CREATE OR REPLACE PROCEDURE GET_CUSTOMER
(
c_id IN NUMBER
)
AS

--declaration of cursor
cursor c is SELECT first_name, country FROM customer WHERE customer_id = c_id;

c_rec customer%rowtype;

BEGIN

open c; -- open cursor

LOOP
-- fetching of data
fetch c INTO c_rec;

EXIT WHEN C%NOTFOUND;
dbms_output.put_line('Name: '|| c_rec.first_name);
dbms_output.put_line('Country: '|| c_rec.country);

END LOOP;

Close c; --closing cursor.
END;

Cursor For Loop:
With cursor FOR loop, the body of the loop is executed for each row returned by the sql query.

Syntax:
FOR customer_rec IN
(Select * from customer where customer_id = 10)
LOOP
Dbms_output.put_line(customer_rec.last_name);
END LOOP;

Example:

CREATE OR REPLACE PROCEDURE GET_CUSTOMER
(
c_id IN NUMBER
)
AS

BEGIN

FOR c_rec IN (SELECT first_name, country FROM customer WHERE customer_id = c_id)
LOOP

dbms_output.put_line('Name: '|| c_rec.first_name);
dbms_output.put_line('Country: '|| c_rec.country);

END LOOP;

END;

Cursor variable and reference cursor:

A cursor variable is a variable that points to a cursor or a result set. We can pass a cursor variable as a arugment to a procedure or function.

Pass a cursor variable back to the host environment that called the program unit - the result set can be consumed for display or other processing.

Syntax:

C_variable SYS_REFCURSOR;

Example:

CREATE OR REPLACE FUNCTION get_names
(
     cust_id IN NUMBER
)
     RETURN SYS_REFCURSOR
IS
     l_return SYS_REFCURSOR;
BEGIN
     OPEN l_return FOR
          SELECT first_name,last_name FROM        customer WHERE customer_id = cust_id;

     RETURN l_return;
END get_names;

CREATE OR REPLACE PROCEDURE DISPLAY_NAMES
IS
C_REC SYS_REFCURSOR;
FNAME VARCHAR2(50);
LNAME VARCHAR2(50);
BEGIN
C_REC := GET_NAMES(10);

LOOP
FETCH C_REC INTO FNAME,LNAME;
EXIT WHEN C_REC%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(FNAME);
DBMS_OUTPUT.PUT_LINE(LNAME);
END LOOP;

CLOSE C_REC;
END;

EXECUTE DISPLAY_NAMES();

Exceptions for cursors:

CURSOR_ALREADY_OPEN: we get this exception when we try to open a cursor thats already open.

INVALID_CURSOR: If we try to reference a cursor that does not exist. This may have happened cause we have executed a FETCH cursor or CLOSE cursor before opening the cursor.

No comments:

Post a Comment

Featured Post

OIC - how can I use XSLT functions to remove leading zeros from numeric and alphanumeric fields?

To remove leading zeros from an numeric field in Oracle Integration Cloud (OIC) using XSLT, you can Use number() Function The number() funct...