DEV Community

Pranav Bakare
Pranav Bakare

Posted on

3 1 1 1 1

Cursor Types in PLSQL -Normal cursor and Reference cursor

Let’s extend the previous example by demonstrating the difference between a normal cursor and a reference cursor, along with a scenario where the reference cursor solves a problem that the normal cursor cannot.

Basics of Cursor;

Key Differences between Normal Cursor and Reference Cursor:

Normal Cursor:

  • A normal cursor is static, meaning it is bound to a fixed SQL query at compile-time.
  • You cannot pass parameters to change the query dynamically.
  • The structure and query are defined at the time of declaration and cannot be changed.

Reference Cursor (REF CURSOR):

  • A reference cursor is dynamic, meaning it allows you to define the query at runtime.
  • You can pass a reference cursor as a parameter to a procedure or function, allowing more flexible query execution.
  • It is a pointer to a query result set, which can be opened for any SELECT statement dynamically.

Problem with Normal Cursor:

With a normal cursor, the query is fixed. Suppose we want to write a PL/SQL procedure where the query could vary based on different conditions, for example, fetching data from different tables or using dynamic conditions. A normal cursor cannot handle such cases easily.

A reference cursor solves this problem by allowing dynamic query assignment at runtime.


Scenario:

We want to create a PL/SQL block that fetches employee details based on a dynamic condition. If the condition is to fetch employees with EMPLOYEE_ID < 103, we use one query. If the condition is to fetch all employees, we use another query.

  1. Using a Normal Cursor (Fixed Query):
    This approach only works when the query is fixed and cannot be changed dynamically.

  2. Using a Reference Cursor (Dynamic Query):
    This approach allows us to dynamically pass queries based on the condition.


Step 1: Create the EMPLOYEES Table and Insert Data (As before)

Table Creation:

CREATE TABLE EMPLOYEES (
    EMPLOYEE_ID   NUMBER(5),
    FIRST_NAME    VARCHAR2(50),
    LAST_NAME     VARCHAR2(50)
);
Enter fullscreen mode Exit fullscreen mode
Insert Data:

INSERT INTO EMPLOYEES (EMPLOYEE_ID, FIRST_NAME, LAST_NAME)
VALUES (101, 'John', 'Doe');

INSERT INTO EMPLOYEES (EMPLOYEE_ID, FIRST_NAME, LAST_NAME)
VALUES (102, 'Jane', 'Smith');

INSERT INTO EMPLOYEES (EMPLOYEE_ID, FIRST_NAME, LAST_NAME)
VALUES (103, 'Mark', 'Taylor');

INSERT INTO EMPLOYEES (EMPLOYEE_ID, FIRST_NAME, LAST_NAME)
VALUES (104, 'Lucy', 'Williams');

Enter fullscreen mode Exit fullscreen mode

Step 2: Demonstrate Using a Normal Cursor (Fixed Query)

In this example, the query is fixed and cannot change dynamically.

PL/SQL Block with a Normal Cursor:

DECLARE
   -- Step 1: Declare a normal cursor (fixed query)
   CURSOR emp_cursor IS
      SELECT EMPLOYEE_ID, FIRST_NAME, LAST_NAME
      FROM EMPLOYEES
      WHERE EMPLOYEE_ID < 103; -- Fixed condition in query

   -- Step 2: Record variable to hold the result of the fetch
   emp_record EMPLOYEES%ROWTYPE;
BEGIN
   -- Step 3: Open the cursor
   OPEN emp_cursor;

   -- Step 4: Fetch data and process
   LOOP
      FETCH emp_cursor INTO emp_record;
      EXIT WHEN emp_cursor%NOTFOUND;

      DBMS_OUTPUT.PUT_LINE
('Employee ID: ' || emp_record.EMPLOYEE_ID ||
                           ', First Name: ' || emp_record.FIRST_NAME ||
                           ', Last Name: ' || emp_record.LAST_NAME);
   END LOOP;

   -- Step 5: Close the cursor
   CLOSE emp_cursor;
END;
Enter fullscreen mode Exit fullscreen mode
Output (Normal Cursor):

Employee ID: 101, First Name: John, Last Name: Doe
Employee ID: 102, First Name: Jane, Last Name: Smith

Enter fullscreen mode Exit fullscreen mode

Limitation:

The query is fixed, so we can only fetch employees with EMPLOYEE_ID < 103. To change the query, we’d need to modify the cursor declaration itself, which isn’t practical in dynamic scenarios.


Step 3: Demonstrate Using a Reference Cursor (Dynamic Query)

Here, we solve the limitation by using a reference cursor that allows us to pass dynamic queries.

PL/SQL Block with a Reference Cursor:

DECLARE
   -- Step 1: Declare a reference cursor (dynamic cursor)
   TYPE ref_cursor_type IS REF CURSOR;
   emp_ref_cursor ref_cursor_type;

   -- Step 2: Record variable to hold the result of the fetch
   emp_record EMPLOYEES%ROWTYPE;

   -- Step 3: Declare a variable to determine the condition dynamically
   emp_condition NUMBER := 103;  
-- This can be changed to different values dynamically
BEGIN
   -- Step 4: Open the reference cursor with dynamic query based on condition
   IF emp_condition < 103 THEN
      OPEN emp_ref_cursor FOR
      SELECT EMPLOYEE_ID, FIRST_NAME, LAST_NAME
      FROM EMPLOYEES
      WHERE EMPLOYEE_ID < emp_condition;
   ELSE
      OPEN emp_ref_cursor FOR
      SELECT EMPLOYEE_ID, FIRST_NAME, LAST_NAME
      FROM EMPLOYEES;
   END IF;

   -- Step 5: Fetch data and process dynamically
   LOOP
      FETCH emp_ref_cursor INTO emp_record;
      EXIT WHEN emp_ref_cursor%NOTFOUND;

      DBMS_OUTPUT.PUT_LINE
('Employee ID: ' || emp_record.EMPLOYEE_ID ||
                           ', First Name: ' || emp_record.FIRST_NAME ||
                           ', Last Name: ' || emp_record.LAST_NAME);
   END LOOP;

   -- Step 6: Close the reference cursor
   CLOSE emp_ref_cursor;
END;
Enter fullscreen mode Exit fullscreen mode
Output (Reference Cursor with Dynamic Condition):

If emp_condition is set to 103:

Employee ID: 101, First Name: John, Last Name: Doe
Employee ID: 102, First Name: Jane, Last Name: Smith
Enter fullscreen mode Exit fullscreen mode
If emp_condition is set to a higher value (e.g., 104), 
then all employees are fetched:

Employee ID: 101, First Name: John, Last Name: Doe
Employee ID: 102, First Name: Jane, Last Name: Smith
Employee ID: 103, First Name: Mark, Last Name: Taylor
Employee ID: 104, First Name: Lucy, Last Name: Williams

Enter fullscreen mode Exit fullscreen mode

Explanation:

Normal Cursor: The query is fixed at compile-time and cannot be changed. This means you cannot use it dynamically to fetch data based on runtime conditions.

Reference Cursor: The query is assigned dynamically at runtime. You can use different queries based on conditions, which makes it much more flexible.


When to Use a Reference Cursor:

  • When you need to execute different queries dynamically at runtime based on certain conditions.
  • When you need to pass a cursor as a parameter to a procedure or function for flexible query execution.
  • When you want to write more generic code that can handle different queries without changing the cursor declaration.

Conclusion:

A reference cursor offers more flexibility than a normal cursor by allowing dynamic query execution, solving the problem of static queries that normal cursors present.

Heroku

Build apps, not infrastructure.

Dealing with servers, hardware, and infrastructure can take up your valuable time. Discover the benefits of Heroku, the PaaS of choice for developers since 2007.

Visit Site

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay