Learning Objectives – after this chapter you will be able to:
  • Explain cursors and distinguish implicit and explicit cursors.
  • Declare, OPEN, FETCH and CLOSE an explicit cursor.
  • Simplify cursor processing with the cursor FOR loop.
  • Use the cursor attributes %FOUND, %NOTFOUND, %ROWCOUNT and %ISOPEN.
  • Pass input arguments to cursors and use FOR UPDATE with WHERE CURRENT OF.
What is a Cursor?

Oracle uses a work area to execute SQL commands and store processing information; a cursor is a name through which PL/SQL accesses this area.

  • Implicit cursor – declared by PL/SQL for every DML command and every query that returns a single row. Its name is SQL; no declaration is needed.
  • Explicit cursor – declared by the programmer for multi-row queries.

A SELECT … INTO succeeds only when it returns exactly one row: no row raises NO_DATA_FOUND, more than one raises TOO_MANY_ROWS, because many values cannot be copied into one variable. An explicit cursor stores the whole set of rows and lets the program fetch one row at a time.

DatabaseSELECT of the cursor
Cursorset of rows + current row
VariablesFETCH copies the current row
Handling an Explicit Cursor
  1. Declare the cursor in the declare section: CURSOR name [(parameters)] IS select [FOR UPDATE [OF columns]];
  2. OPEN it – executes the SELECT and places the rows in the cursor.
  3. FETCH one row at a time INTO variables (one variable per column, matching types), inside a loop.
  4. CLOSE it – releases the resources.
OPEN – FETCH – CLOSE
declare
   cursor course_det is
      select ccode, name, fee from courses;
   v_ccode courses.ccode%type;
   v_name  courses.name%type;
   v_fee   courses.fee%type;
begin
   open course_det;
   loop
      fetch course_det into v_ccode, v_name, v_fee;
      exit when course_det%notfound;          -- previous FETCH failed: end of cursor
      dbms_output.put_line(v_ccode || ' ' || v_fee);
   end loop;
   close course_det;
end;
Cursor FOR Loop

The cursor FOR loop automates opening the cursor, fetching each row, terminating at the end and closing the cursor. Its record variable is declared automatically as cursor%ROWTYPE, is available only inside the loop, and its fields are accessed as rec.column.

Sample program – update each course fee by number of students
declare
   cursor courses_cursor is
      select b.ccode, count(*) cnt
      from batches b, students s
      where b.bcode = s.bcode
      group by b.ccode;
   v_per number(5,2);
begin
   for rec in courses_cursor loop          -- rec declared automatically
      if rec.cnt > 20 then
         v_per := 1.15;                    -- +15%
      elsif rec.cnt > 10 then
         v_per := 1.10;                    -- +10%
      else
         v_per := 0.95;                    -- -5%
      end if;
      update courses set fee = fee * v_per where ccode = rec.ccode;
   end loop;
end;
The PDF’s listing of this program refers to c.ccode without COURSES in the FROM clause and uses 0.90 for the “otherwise” case; the version above joins only BATCHES and STUDENTS and follows the PDF’s table (5% decrease).
Implicit Cursor and Cursor Attributes

OPEN, FETCH and CLOSE cannot be used with the implicit cursor SQL, but its attributes describe the most recent SQL statement. Syntax: cursor_name%attribute.

AttributeExplicit cursorImplicit cursor (SQL)
%NOTFOUNDTRUE if the previous FETCH failedTRUE if the previous DML affected no row
%FOUNDTRUE if the previous FETCH succeededTRUE if the previous DML affected any row
%ROWCOUNTRows fetched so farRows affected by the most recent DML
%ISOPENTRUE if the cursor is open– (listed for explicit cursors in the notes)
Using SQL%ROWCOUNT (SQL%NOTFOUND tells whether UPDATE/DELETE changed nothing)
begin
   update courses set fee = fee * 1.1 where duration > 25;
   if sql%rowcount > 5 then        -- more than 5 rows changed
      rollback;
   else
      commit;
   end if;
end;
Input Arguments (Parameterised Cursors)

Parameters are declared with the cursor and values are passed when it is opened, so the same cursor can represent different sets of rows. Give only the datatype, without size (VARCHAR2, not VARCHAR2(10)).

declare
   cursor batch_cursor (pccode varchar2) is
      select * from batches where ccode = pccode;
begin
   open batch_cursor('ora');   -- batches of Oracle
   close batch_cursor;
   open batch_cursor('vb');    -- reopened for another course
   close batch_cursor;

   for rec in batch_cursor('ora') loop    -- argument in a cursor FOR loop
      null;
   end loop;
end;
FOR UPDATE and WHERE CURRENT OF

Oracle locks rows automatically while changing them. FOR UPDATE in the cursor’s SELECT locks all the cursor’s rows when the cursor is opened, before they are updated or deleted. WHERE CURRENT OF cursor in UPDATE/DELETE refers to the row last fetched; it requires FOR UPDATE.

declare
   cursor course_details is
      select ccode, name, fee from courses
      for update of fee;
begin
   for rec in course_details loop
      update courses set fee = rec.fee * 1.05
      where current of course_details;
   end loop;
end;
Key Takeaways
  • Single-row SELECT/DML use the implicit cursor SQL; multi-row queries need an explicit cursor.
  • Explicit cursor: declare → open → fetch (loop, exit on %NOTFOUND) → close; or use a cursor FOR loop.
  • SQL%ROWCOUNT / SQL%NOTFOUND report the effect of the last DML.
  • FOR UPDATE locks rows at OPEN; WHERE CURRENT OF changes the fetched row.
Chapter 18 Notes (PDF)
ch18.pdf 13 pages 302 KB Open in PDF Viewer (Free Tool)

Your browser cannot show this PDF here. Open Chapter 18 Notes (PDF)

ch18.pdfKeys: ← → page · + − zoom · F full screen
Question / Answer (15 questions)

Moderate-level questions based on the Chapter 18 notes (PDF). Click a question to see the answer.

Answer : Oracle uses a work area to execute SQL commands and store processing information. A cursor is a name through which PL/SQL accesses this area.

Answer : PL/SQL declares an implicit cursor, named SQL, for every DML command and every query that returns a single row; it needs no declaration. An explicit cursor is declared by the programmer and is required whenever a SELECT in PL/SQL has to retrieve more than one row.

Answer : A SELECT ... INTO in PL/SQL succeeds only when it retrieves exactly one row – no row raises NO_DATA_FOUND and more than one raises TOO_MANY_ROWS – because multiple values for a column cannot be copied into a single variable. An explicit cursor stores the collection of rows and allows the program to fetch and process one row at a time.

Answer : Declare the cursor in the declare section with its SELECT; open it with OPEN in the executable part; fetch one row at a time with FETCH (inside a loop); and close it with CLOSE after all records are fetched and processed.

Answer : OPEN cursor_name [(input arguments)] executes the SELECT command associated with the cursor and places the rows retrieved by the query into the cursor.

Answer : FETCH cursor_name INTO variable-1, variable-2, ... takes the data of the current row of the cursor and copies the column values into the variables. There must be one variable for each column of the cursor and the datatypes must match. It is used inside a loop to read rows repeatedly.

Answer : After each FETCH use EXIT WHEN cursor_name%NOTFOUND – NOTFOUND returns TRUE when the previous FETCH did not read a row. CLOSE cursor_name closes the cursor and releases the resources associated with it.

Answer : FOR rowtype_variable IN cursor_name LOOP statements; END LOOP; is a FOR loop meant for cursors. It automatically opens the cursor, fetches rows one at a time, terminates the loop when all rows are fetched and closes the cursor.

Answer : It is declared automatically as cursor_name%ROWTYPE, has the columns of the cursor as fields, and is available only inside the loop. A column of the current row is accessed as rowtype_variable.columnname, e.g. rec.fee.

Answer : Oracle implicitly opens the cursor named SQL for each SQL statement not associated with an explicit cursor. OPEN, FETCH and CLOSE cannot be used with it, but its attributes give information about the most recently executed SQL statement, e.g. IF SQL%NOTFOUND after an UPDATE.

Answer : %NOTFOUND – TRUE if the previous fetch failed; %FOUND – TRUE if the previous fetch succeeded; %ROWCOUNT – number of rows fetched from the cursor so far; %ISOPEN – TRUE if the cursor is currently open. Syntax: cursor_name%attribute.

Answer : SQL%NOTFOUND is TRUE if the previous DML operation did not affect any row; SQL%FOUND is TRUE if it affected any row; SQL%ROWCOUNT gives the number of rows affected by the most recent DML operation. They are how we know whether the most recent DML affected any row.

Answer : They are parameters declared with the cursor, e.g. CURSOR batch_cursor (pccode VARCHAR2) IS SELECT * FROM batches WHERE ccode = pccode, whose values are passed when the cursor is opened: OPEN batch_cursor('ora') or FOR rec IN batch_cursor('ora'). The same cursor can represent different sets of records at different times. The size of the parameter datatype must not be given.

Answer : Oracle locks rows automatically while manipulating them. FOR UPDATE [OF columns] in the cursor’s SELECT overrides the default locking by locking all records retrieved by the cursor at the time of opening it, so that they are not locked by others before we update or delete them.

Answer : WHERE CURRENT OF cursor_name refers to the current row of the cursor (the row last fetched), so UPDATE or DELETE acts on that row. FOR UPDATE must be given in the cursor declaration to use CURRENT OF.
MCQ Test : Check Your Understanding (5 questions)

Select an option and press Check Answer, or answer all questions and press Submit Test to see your score. Each answer comes with an explanation.

Q1. Which attribute tells how many rows have been fetched from a cursor so far?

Show Answer

Correct Answer : C. %ROWCOUNT
%ROWCOUNT returns the number of rows fetched so far (for SQL: rows affected by the last DML).

Q2. What is the name of the implicit cursor?

Show Answer

Correct Answer : D. SQL
PL/SQL’s implicit cursor is referred to as SQL, e.g. SQL%ROWCOUNT.

Q3. Which of these is NOT done automatically by a cursor FOR loop?

Show Answer

Correct Answer : A. Declaring the cursor’s SELECT statement
The cursor must still be declared (or written inline); the FOR loop opens, fetches, exits and closes automatically.

Q4. Which clause must be present in the cursor declaration to use WHERE CURRENT OF?

Show Answer

Correct Answer : B. FOR UPDATE
FOR UPDATE must be given to refer to the current row with CURRENT OF.

Q5. How is the size of a cursor parameter specified?

Show Answer

Correct Answer : C. It is not specified – only the datatype (VARCHAR2)
The size of datatypes of input arguments should not be given.

Bibliography/References

The chapter notes PDF is the course study material and is credited to its author below. The explanations, questions and MCQs on this page are original study aids written for this course from the topics covered in that PDF. The other works are cited for verification and further reading. Oracle, SQL*Plus and PL/SQL are trademarks of Oracle Corporation; other names belong to their respective owners.

  1. Srikanth, P. (n.d.). Oracle For Beginners (chapter notes – the PDF shown on each chapter page). Srikanth Technologies. http://www.srikanthtechnologies.com/
  2. Oracle Corporation. (n.d.). Oracle Database PL/SQL Language Reference, 19c. https://docs.oracle.com/en/database/oracle/oracle-database/19/lnpls/
  3. Feuerstein, S., & Pribyl, B. (2014). Oracle PL/SQL Programming (6th ed.). O’Reilly Media.