Understanding WHERE CURRENT OF Clause In Oracle Database

HINT_ORACLE_JOIN

If you plan on updating or deleting records that have been referenced by a SELECT FOR UPDATE statement, you can use the WHERE CURRENT OF statement.

WHERE CURRENT OF works ONLY with SELECT FOR UPDATE/SELECT FOR UPDATE NOWAIT query.

As soon as a cursor with a FOR UPDATE clause is opened, all rows identified in the result set of the cursor are locked and remain locked until your session ends or your code explicitly issues either a COMMIT or a ROLLBACK. When either of these occurs,the locks on the rows are released. As a result, you cannot execute another FETCH against a FOR UPDATE cursor after a COMMIT or ROLLBACK. You will have lost your position in the cursor.

If you ever need to execute a COMMIT or ROLLBACK as you FETCH records from a SELECT FOR UPDATE cursor, you should include code (such as a loop EXIT or other conditional logic) to halt any further fetches from the cursor.

SQL> CREATE TABLE test_emp
  2  (
  3    name  VARCHAR2(30 BYTE),
  4    salary NUMBER
  5  );

Table created.

SQL> INSERT ALL
  2  INTO test_emp (name,salary) VALUES ('AAA',1000)
  3  INTO test_emp (name,salary) VALUES ('BBB',2000)
  4  INTO test_emp (name,salary) VALUES ('CCC',3000)
  5  INTO test_emp (name,salary) VALUES ('AAA',4000)
  6  INTO test_emp (name,salary) VALUES ('EEE',5000)
  7  INTO test_emp (name,salary) VALUES ('BBB',6000)
  8  SELECT * FROM DUAL;

6 rows created.

SQL> COMMIT;

Commit complete.

SQL> SELECT * FROM test_emp;

NAME                               SALARY
------------------------------ ----------
AAA                                  1000
BBB                                  2000
CCC                                  3000
AAA                                  4000
EEE                                  5000
BBB                                  6000

SQL> DECLARE
  2     CURSOR cur_emp IS
  3          SELECT * FROM test_emp;
  4  BEGIN
  5        FOR rec IN cur_emp
  6       LOOP
  7          UPDATE test_emp SET salary = salary + 1000
  8             WHERE name = rec.name;
  9       END LOOP;
 10  END;
 11  /

PL/SQL procedure successfully completed.

SQL> SELECT * FROM test_emp;

NAME                               SALARY
------------------------------ ----------
AAA                                  3000
BBB                                  4000
CCC                                  4000
AAA                                  6000
EEE                                  6000
BBB                                  8000

SQL> DELETE FROM test_emp;

6 rows deleted.

SQL> COMMIT;

Commit complete.

SQL> INSERT ALL
  2  INTO test_emp (name,salary) VALUES ('AAA',1000)
  3  INTO test_emp (name,salary) VALUES ('BBB',2000)
  4  INTO test_emp (name,salary) VALUES ('CCC',3000)
  5  INTO test_emp (name,salary) VALUES ('AAA',4000)
  6  INTO test_emp (name,salary) VALUES ('EEE',5000)
  7  INTO test_emp (name,salary) VALUES ('BBB',6000)
  8  SELECT * FROM DUAL;

6 rows created.

SQL> COMMIT;

Commit complete.

SQL> SELECT * FROM test_emp;

NAME                               SALARY
------------------------------ ----------
AAA                                  1000
BBB                                  2000
CCC                                  3000
AAA                                  4000
EEE                                  5000
BBB                                  6000

SQL> DECLARE
  2     CURSOR cur_emp IS
  3          SELECT * FROM test_emp FOR UPDATE;
  4  BEGIN
  5        FOR rec IN cur_emp
  6       LOOP
  7          UPDATE test_emp SET salary = salary + 1000
  8             WHERE CURRENT OF cur_emp;
  9       END LOOP;
 10  END;
 11  /

PL/SQL procedure successfully completed.

SQL> SELECT * FROM test_emp;

NAME                               SALARY
------------------------------ ----------
AAA                                  2000
BBB                                  3000
CCC                                  4000
AAA                                  5000
EEE                                  6000
BBB                                  7000

SQL> DECLARE
  2     CURSOR cur_emp IS
  3          SELECT * FROM test_emp FOR UPDATE;
  4  BEGIN
  5        FOR rec IN cur_emp
  6       LOOP
  7          UPDATE test_emp SET salary = salary + 1000
  8             WHERE CURRENT OF cur_emp;
  9                COMMIT;
 10       END LOOP;
 11  END;
 12  /
DECLARE
*
ERROR at line 1:
ORA-01002: fetch out of sequence
ORA-06512: at line 5

SQL> SELECT * FROM test_emp;

NAME                               SALARY
------------------------------ ----------
AAA                                  3000
BBB                                  3000
CCC                                  4000
AAA                                  5000
EEE                                  6000
BBB                                  7000

SQL> DECLARE
  2     CURSOR cur_emp IS
  3          SELECT * FROM test_emp FOR UPDATE;
  4  BEGIN
  5        FOR rec IN cur_emp
  6       LOOP
  7          UPDATE test_emp SET salary = salary + 1000
  8             WHERE CURRENT OF cur_emp;
  9                COMMIT;
 10                       EXIT;
 11       END LOOP;
 12  END;
 13  /

PL/SQL procedure successfully completed.

SQL> SELECT * FROM test_emp;

NAME                               SALARY
------------------------------ ----------
AAA                                  4000
BBB                                  3000
CCC                                  4000
AAA                                  5000
EEE                                  6000
BBB                                  7000
SQL> SELECT * FROM emp;

     EMPNO ENAME      JOB              MGR HIREDATE         SAL       COMM     DEPTNO
---------- ---------- --------- ---------- --------- ---------- ---------- ----------
      7839 KING       PRESIDENT            17-NOV-81       5000                    10
      7698 BLAKE      MANAGER         7839 01-MAY-81       2850                    30
      7782 CLARK      MANAGER         7839 09-JUN-81       2450                    10
      7566 JONES      MANAGER         7839 02-APR-81       2975                    20
      7788 SCOTT      ANALYST         7566 19-APR-87       3000                    20
      7902 FORD       ANALYST         7566 03-DEC-81       3000                    20
      7369 SMITH      CLERK           7902 17-DEC-80        800                    20
      7499 ALLEN      SALESMAN        7698 20-FEB-81       1600        300         30
      7521 WARD       SALESMAN        7698 22-FEB-81       1250        500         30
      7654 MARTIN     SALESMAN        7698 28-SEP-81       1250       1400         30
      7844 TURNER     SALESMAN        7698 08-SEP-81       1500          0         30
      7876 ADAMS      CLERK           7788 23-MAY-87       1100                    20
      7900 JAMES      CLERK           7698 03-DEC-81        950                    30
      7934 MILLER     CLERK           7782 23-JAN-82       1300                    10

14 rows selected.

SQL> UPDATE emp set ename = 'KING' WHERE empno IN (7698,7782,7566,7788);

4 rows updated.

SQL> UPDATE emp set ename = 'QUEEN' WHERE empno IN (7902,7369,7499,7521,7654);

5 rows updated.

SQL> UPDATE emp set ename = 'SERVANT' WHERE empno IN (7844,7876,7900,7934);

4 rows updated.

SQL> SELECT * FROM emp;

     EMPNO ENAME      JOB              MGR HIREDATE         SAL       COMM     DEPTNO
---------- ---------- --------- ---------- --------- ---------- ---------- ----------
      7839 KING       PRESIDENT            17-NOV-81       5000                    10
      7698 KING       MANAGER         7839 01-MAY-81       2850                    30
      7782 KING       MANAGER         7839 09-JUN-81       2450                    10
      7566 KING       MANAGER         7839 02-APR-81       2975                    20
      7788 KING       ANALYST         7566 19-APR-87       3000                    20
      7902 QUEEN      ANALYST         7566 03-DEC-81       3000                    20
      7369 QUEEN      CLERK           7902 17-DEC-80        800                    20
      7499 QUEEN      SALESMAN        7698 20-FEB-81       1600        300         30
      7521 QUEEN      SALESMAN        7698 22-FEB-81       1250        500         30
      7654 QUEEN      SALESMAN        7698 28-SEP-81       1250       1400         30
      7844 SERVANT    SALESMAN        7698 08-SEP-81       1500          0         30
      7876 SERVANT    CLERK           7788 23-MAY-87       1100                    20
      7900 SERVANT    CLERK           7698 03-DEC-81        950                    30
      7934 SERVANT    CLERK           7782 23-JAN-82       1300                    10

14 rows selected.

SQL> DECLARE
  2     CURSOR cur_emp IS
  3          SELECT * FROM emp;
  4  BEGIN
  5        FOR rec IN cur_emp
  6       LOOP
  7          UPDATE emp SET sal = sal + 1 WHERE ename = rec.ename;
  8       END LOOP;
  9  END;
 10  /

PL/SQL procedure successfully completed.

SQL> SELECT * FROM emp;

     EMPNO ENAME      JOB              MGR HIREDATE         SAL       COMM     DEPTNO
---------- ---------- --------- ---------- --------- ---------- ---------- ----------
      7839 KING       PRESIDENT            17-NOV-81       5005                    10
      7698 KING       MANAGER         7839 01-MAY-81       2855                    30
      7782 KING       MANAGER         7839 09-JUN-81       2455                    10
      7566 KING       MANAGER         7839 02-APR-81       2980                    20
      7788 KING       ANALYST         7566 19-APR-87       3005                    20
      7902 QUEEN      ANALYST         7566 03-DEC-81       3005                    20
      7369 QUEEN      CLERK           7902 17-DEC-80        805                    20
      7499 QUEEN      SALESMAN        7698 20-FEB-81       1605        300         30
      7521 QUEEN      SALESMAN        7698 22-FEB-81       1255        500         30
      7654 QUEEN      SALESMAN        7698 28-SEP-81       1255       1400         30
      7844 SERVANT    SALESMAN        7698 08-SEP-81       1504          0         30
      7876 SERVANT    CLERK           7788 23-MAY-87       1104                    20
      7900 SERVANT    CLERK           7698 03-DEC-81        954                    30
      7934 SERVANT    CLERK           7782 23-JAN-82       1304                    10

14 rows selected.

SQL> DECLARE
  2     CURSOR cur_emp IS
  3          SELECT * FROM emp;
  4  BEGIN
  5        FOR rec IN cur_emp
  6       LOOP
  7          UPDATE emp SET sal = sal + 1 WHERE CURRENT OF cur_emp;
  8       END LOOP;
  9  END;
 10  /
UPDATE emp SET sal = sal + 1 WHERE CURRENT OF cur_emp;
                                                      *
ERROR at line 7:
ORA-06550: line 7, column 55:
PLS-00404: cursor 'CUR_EMP' must be declared with FOR UPDATE to use with CURRENT OF
ORA-06550: line 7, column 55:
PL/SQL: ORA-00904: : invalid identifier
ORA-06550: line 7, column 9:
PL/SQL: SQL Statement ignored

SQL> DECLARE
  2     CURSOR cur_emp IS
  3          SELECT * FROM emp
  4          FOR UPDATE;
  5  BEGIN
  6        FOR rec IN cur_emp
  7       LOOP
  8          UPDATE emp SET sal = sal + 1 WHERE CURRENT OF cur_emp;
  9       END LOOP;
 10  END;
 11  /

PL/SQL procedure successfully completed.

SQL> SELECT * FROM emp;

     EMPNO ENAME      JOB              MGR HIREDATE         SAL       COMM     DEPTNO
---------- ---------- --------- ---------- --------- ---------- ---------- ----------
      7839 KING       PRESIDENT            17-NOV-81       5006                    10
      7698 KING       MANAGER         7839 01-MAY-81       2856                    30
      7782 KING       MANAGER         7839 09-JUN-81       2456                    10
      7566 KING       MANAGER         7839 02-APR-81       2981                    20
      7788 KING       ANALYST         7566 19-APR-87       3006                    20
      7902 QUEEN      ANALYST         7566 03-DEC-81       3006                    20
      7369 QUEEN      CLERK           7902 17-DEC-80        806                    20
      7499 QUEEN      SALESMAN        7698 20-FEB-81       1606        300         30
      7521 QUEEN      SALESMAN        7698 22-FEB-81       1256        500         30
      7654 QUEEN      SALESMAN        7698 28-SEP-81       1256       1400         30
      7844 SERVANT    SALESMAN        7698 08-SEP-81       1505          0         30
      7876 SERVANT    CLERK           7788 23-MAY-87       1105                    20
      7900 SERVANT    CLERK           7698 03-DEC-81        955                    30
      7934 SERVANT    CLERK           7782 23-JAN-82       1305                    10

14 rows selected.
SQL> SELECT * FROM emp;

     EMPNO ENAME      JOB              MGR HIREDATE         SAL       COMM     DEPTNO
---------- ---------- --------- ---------- --------- ---------- ---------- ----------
      7839 KING       PRESIDENT            17-NOV-81       5006                    10
      7698 KING       MANAGER         7839 01-MAY-81       2856                    30
      7782 KING       MANAGER         7839 09-JUN-81       2456                    10
      7566 KING       MANAGER         7839 02-APR-81       2981                    20
      7788 KING       ANALYST         7566 19-APR-87       3006                    20
      7902 QUEEN      ANALYST         7566 03-DEC-81       3006                    20
      7369 QUEEN      CLERK           7902 17-DEC-80        806                    20
      7499 QUEEN      SALESMAN        7698 20-FEB-81       1606        300         30
      7521 QUEEN      SALESMAN        7698 22-FEB-81       1256        500         30
      7654 QUEEN      SALESMAN        7698 28-SEP-81       1256       1400         30
      7844 SERVANT    SALESMAN        7698 08-SEP-81       1505          0         30
      7876 SERVANT    CLERK           7788 23-MAY-87       1105                    20
      7900 SERVANT    CLERK           7698 03-DEC-81        955                    30
      7934 SERVANT    CLERK           7782 23-JAN-82       1305                    10

14 rows selected.

SQL> DECLARE
  2     CURSOR cur_emp IS
  3          SELECT * FROM emp
  4          FOR UPDATE;
  5  BEGIN
  6        FOR rec IN cur_emp
  7       LOOP
  8          UPDATE emp SET sal = sal + 1 WHERE ename = rec.ename;
  9       END LOOP;
 10  END;
 11  /

PL/SQL procedure successfully completed.

SQL>  SELECT * FROM emp;

     EMPNO ENAME      JOB              MGR HIREDATE         SAL       COMM     DEPTNO
---------- ---------- --------- ---------- --------- ---------- ---------- ----------
      7839 KING       PRESIDENT            17-NOV-81       5011                    10
      7698 KING       MANAGER         7839 01-MAY-81       2861                    30
      7782 KING       MANAGER         7839 09-JUN-81       2461                    10
      7566 KING       MANAGER         7839 02-APR-81       2986                    20
      7788 KING       ANALYST         7566 19-APR-87       3011                    20
      7902 QUEEN      ANALYST         7566 03-DEC-81       3011                    20
      7369 QUEEN      CLERK           7902 17-DEC-80        811                    20
      7499 QUEEN      SALESMAN        7698 20-FEB-81       1611        300         30
      7521 QUEEN      SALESMAN        7698 22-FEB-81       1261        500         30
      7654 QUEEN      SALESMAN        7698 28-SEP-81       1261       1400         30
      7844 SERVANT    SALESMAN        7698 08-SEP-81       1509          0         30
      7876 SERVANT    CLERK           7788 23-MAY-87       1109                    20
      7900 SERVANT    CLERK           7698 03-DEC-81        959                    30
      7934 SERVANT    CLERK           7782 23-JAN-82       1309                    10

14 rows selected.
SQL> CREATE TABLE test_emp
  2  (
  3    name  VARCHAR2(30 BYTE) PRIMARY KEY,
  4    salary NUMBER
  5  );

Table created.

SQL> INSERT ALL
  2  INTO test_emp (name,salary) VALUES ('AAA',1000)
  3  INTO test_emp (name,salary) VALUES ('BBB',2000)
  4  INTO test_emp (name,salary) VALUES ('CCC',3000)
  5  INTO test_emp (name,salary) VALUES ('DDD',4000)
  6  INTO test_emp (name,salary) VALUES ('EEE',5000)
  7  INTO test_emp (name,salary) VALUES ('FFF',6000)
  8  SELECT * FROM DUAL;

6 rows created.

SQL> COMMIT;

Commit complete.

SQL> SELECT * FROM test_emp;

NAME                               SALARY
------------------------------ ----------
AAA                                  1000
BBB                                  2000
CCC                                  3000
DDD                                  4000
EEE                                  5000
FFF                                  6000

6 rows selected.

SQL> DECLARE
  2     CURSOR cur_emp IS
  3          SELECT * FROM test_emp;
  4  BEGIN
  5        FOR rec IN cur_emp
  6       LOOP
  7          UPDATE test_emp SET salary = salary + 1 WHERE name = rec.name;
  8       END LOOP;
  9  END;
 10  /

PL/SQL procedure successfully completed.

SQL> COMMIT;

Commit complete.

SQL> SELECT * FROM test_emp;

NAME                               SALARY
------------------------------ ----------
AAA                                  1001
BBB                                  2001
CCC                                  3001
DDD                                  4001
EEE                                  5001
FFF                                  6001

6 rows selected.

SQL> DECLARE
  2     CURSOR cur_emp IS
  3          SELECT * FROM test_emp
  4          FOR UPDATE;
  5  BEGIN
  6        FOR rec IN cur_emp
  7       LOOP
  8          UPDATE test_emp SET salary = salary + 1 WHERE CURRENT OF cur_emp;
  9       END LOOP;
 10  END;
 11  /

PL/SQL procedure successfully completed.

SQL> COMMIT;

Commit complete.

SQL> SELECT * FROM test_emp;

NAME                               SALARY
------------------------------ ----------
AAA                                  1002
BBB                                  2002
CCC                                  3002
DDD                                  4002
EEE                                  5002
FFF                                  6002

6 rows selected.

SQL> DECLARE
  2     CURSOR cur_emp IS
  3          SELECT * FROM test_emp
  4          FOR UPDATE;
  5  BEGIN
  6        FOR rec IN cur_emp
  7       LOOP
  8          UPDATE test_emp SET salary = salary + 1 WHERE CURRENT OF cur_emp;
  9          COMMIT;
 10       END LOOP;
 11  END;
 12  /
DECLARE
*
ERROR at line 1:
ORA-01002: fetch out of sequence
ORA-06512: at line 6
ORA-06512: at line 6

SQL> SELECT * FROM test_emp;

NAME                               SALARY
------------------------------ ----------
AAA                                  1003
BBB                                  2002
CCC                                  3002
DDD                                  4002
EEE                                  5002
FFF                                  6002

6 rows selected.

SQL> DECLARE
  2     CURSOR cur_emp IS
  3          SELECT * FROM test_emp
  4          FOR UPDATE;
  5  BEGIN
  6        FOR rec IN cur_emp
  7       LOOP
  8          UPDATE test_emp SET salary = salary + 1 WHERE CURRENT OF cur_emp;
  9          COMMIT;
 10          EXIT;
 11       END LOOP;
 12  END;
 13  /

PL/SQL procedure successfully completed.

SQL> SELECT * FROM test_emp;

NAME                               SALARY
------------------------------ ----------
AAA                                  1004
BBB                                  2002
CCC                                  3002
DDD                                  4002
EEE                                  5002
FFF                                  6002

6 rows selected.

Shoumadip Das

Hi Folks, I am Shoumadip Das hailing from Kolkata, India welcoming you to explore my blog www.oraclemasterpiece.com. I am a self motivated and successful professional working in a leading IT Giant for more than 10 years.My area of expertise includes –

  • Oracle Database Programming (SQL & PL/SQL)
  • Perl Programming
  • Unix Programming

Read More

Leave a Reply

Your email address will not be published. Required fields are marked *