It is quite inevitable to do a sincere PL/SQL programming without sound understanding of cursors. The main agenda of this post is to discuss about different types of cursors and its uses in PL/SQL. It is the reference data type of PL/SQL as mentioned in previous post where we discussed about Data types in PL/SQL.
What is cursor:- When a SQL statement is executed from PL/SQL program unit the Oracle database server assigns a private work area for that statement and that area contains processing info of that SQL statement and information about data returned. The PL/SQL cursor is a pointer to this private SQL area - i.e : Using this cursor we assign name to that private area and we have a handle to control the information stored.
For example:- when we execute a select statement in PL/SQL, select statement returns a result-set(a virtual table which has same structure as table(rows and columns)). The cursor points to this virtual table and this virtual table is transient(not permanent), it only exist for the duration of SELECT statement execution .
In PL/SQL cursors can be broadly classified in following category :-
1. Static cursor - cursor bound to a specific SQL statement(SQL decided at compile time itself), it is similar to final reference in Java. Static cursor can be further classified in two category-
Both Static cursor and cursor Variable are collectively termed as Session cursors and it's existence is util session persist.Session cursor lives in session memory until the session ends.Before going into detail of each cursor type, let understand life cycle of cursors / operations performed on cursor.
Life cycle of PL/SQL Cursor:- Each cursor regardless of its types passes through same set of operation when used in PL/SQL program unit - 1. OPEN 2. FETCH 3. CLOSE. Following diagram captures life cycle of Cursor.
OPEN operation:- When you open a cursor,SQL statement in private memory area is ready to execute inside SQL engine and after execution, pointer to the active row is set to the first row of result set.
FETCH operation:- FETCH command retrieves current row from result set and PL/SQL moves pointer to next row. If there are no more rows to retrieve, then FETCH does not raise any exception, it simply does nothing.
CLOSE operation:- The CLOSE command closes the cursor and releases all memory used by the cursor.Once the cursor is closed, the cursor no longer has a result set.
Note:- For implicit cursor all the above operation is performed by PL/SQL engine, however all operation is carried out by programmer in the case of Explicit cursor.
Programmer does not have control over life cycle of implicit cursor(cannot perform OPEN, FECT and CLOSE operation), however for each SQL DML statements (INSERT, UPDATE, DELETE and one row returning SELECT) that database server executes opens an implicit cursor called "SQL" and attributes associated with it can be used to get information about the most recently executed SQL statement. The SQL cursor has the four attributes :
2. When a SELECT statement is executed and it returns single row, here programmer has a choice to use implicit or explicit cursor. It is recommended that always use explicit cursor for select statement even for single row query. (Why? - Read point# 3).
3. If an implicit SELECT statement returns more than one row, it raises the TOO_MANY_ROWS exception and current block execution terminates and control reaches in exception block.
Now lets write a sample PL/SQL program and summarise implicit cursor understanding and familiarise with implicit cursor "SQL" attributes handling:- Execute the following PL/SQL program in SQLPLUS or SQL developer. How to execute PL/SQL program in SQL*PLUS or SQL developer?
Here I have executed it from SQL*PLUS(Created a file cursor_1.sql with above sample codes and executed via SQL*PLUS) and sample output is as follwos.
=========Sample output==============
SQL> @cursor_1.sql
Yes, one row inserted successfully!!
Yes,rows updated successfully!!
SQL cursor opened!!
PL/SQL procedure successfully completed.
==================================
In above program, an insert statement is executed and check for SQL%FOUND returns true and display output accordingly. Similarly, when an update query is executed, it will updated multiple rows in database so, check of SQL%FOUND returns true. Finally,when check for SQL%ROWCOUNT
is done it also return true since SQL cursor has been opened in this session(for Insert and Update).Please take a note of following points about above program.
Do we really need explicit cursor for update,delete and insert ?- No, attributes associated with implicit cursor "SQL" has sufficient information to understand whether these operation has been performed of not, as we saw in previous sample example.
With explicit cursor programmer has complete control over state of cursor and its attributes like FOUND, NOTFOUND, ISOPEN and ROWCOUNT gives information for efficient cursor processing. Let's write a sample program to understand life cycle of cursor and how does PL/SQ Loop can be used to iterate over a cursor.
===================Sample output==========================
First name of employee is Steven and email is SKING@devinline.com
First name of employee is Neena and email is NKOCHHAR@devinline.com
First name of employee is Lex and email is LDEHAAN@devinline.com
First name of employee is NIKHIL and email is NIKSR@devinline.com
========================================================
In above program, an explicit cursor is declared with a select statement in declaration block along with a variable declaration of Employee row type. Before opening cursor, it is verified that cursor is open or not , if it is not open then open it and fetch rows and assign values into employee row type variable. NOTFOUND attribute of cursor is checked to exit from loop(if no more record is available in result set poined by cursor).
1. Cursor cannot be used as a variable.It means, it cannot be assigned to another variable and it cannot be assigned any value other than a select statement.
2. SELECT statement pointed by cursor does not necessarily only contain columns of table, it can be a aliased values or modified value too. Generally, column aliases are done when we manipulate column and want to display effective value as column name like following example:
3.In PL/SQL table column always gets preference over local variable of same name, so naming convention is important to follow to avoid such problem. Local variable not used here, database column gets preference.
4. It is good practice to close opened cursor when they are not needed any more, because each cursor consume some memory in shared global area depending on size of result set it it refereeing to.When an instance of database server starts parameter file (init.ora) specifies maximum no of cursors allowed to be open (default value is 50) in a given session. If at any occasion, maximum limit crosses it throws an exception "ORA-01000: maximum open cursors exceeded".
Note: No error or exception arise, if we do not close cursor. However, in order to avoid unfortunate condition it is good to close cursor after its use.
5. Explicit cursor attributes:- The information about current status of cursor is obtained from cursor attributes.Following table describes them in detail:
Always use these attributes in PL/SQL code , if used in SQL context it will throw exception.For detail refer this. As explained earlier implicit cursor SQl also posses these attributes, however there are noticeable differences between them. Read Difference between implicit and explicit cursor attributes.
This is all about explicit and implicit cursor in PL/SQL. In next post a versitile cursor type termed as - cursor variable, will be discussed.
Previous: PL/SQL Record Next: PL/SQL Cursor variable
What is cursor:- When a SQL statement is executed from PL/SQL program unit the Oracle database server assigns a private work area for that statement and that area contains processing info of that SQL statement and information about data returned. The PL/SQL cursor is a pointer to this private SQL area - i.e : Using this cursor we assign name to that private area and we have a handle to control the information stored.
Select statement execution in PL/SQL and result set pointed by cursor. |
Note:- In PL/SQL we have two different type of SQL statements,Static SQL and Dynamic SQL. Read difference between Static and Dynamic SQL. The discussion of the cursors in PL/SQL is restricted to Static SQL ONLY.
In PL/SQL cursors can be broadly classified in following category :-
1. Static cursor - cursor bound to a specific SQL statement(SQL decided at compile time itself), it is similar to final reference in Java. Static cursor can be further classified in two category-
- Implicit cursor - Managed by PL/SQL itself and programmer has limited control over it.
PL/SQL assign an implicit cursor for each SQL DML statement like Insert, Update, Delete and Select statement returning only one row. - Explicit cursor.- Managed by programmer and has programmer has complete control over it.
Both Static cursor and cursor Variable are collectively termed as Session cursors and it's existence is util session persist.Session cursor lives in session memory until the session ends.Before going into detail of each cursor type, let understand life cycle of cursors / operations performed on cursor.
Life cycle of PL/SQL Cursor:- Each cursor regardless of its types passes through same set of operation when used in PL/SQL program unit - 1. OPEN 2. FETCH 3. CLOSE. Following diagram captures life cycle of Cursor.
Life cycle of PL/SQL Cursor - OPEN, FETCH and CLOSE operation. |
FETCH operation:- FETCH command retrieves current row from result set and PL/SQL moves pointer to next row. If there are no more rows to retrieve, then FETCH does not raise any exception, it simply does nothing.
CLOSE operation:- The CLOSE command closes the cursor and releases all memory used by the cursor.Once the cursor is closed, the cursor no longer has a result set.
Note:- For implicit cursor all the above operation is performed by PL/SQL engine, however all operation is carried out by programmer in the case of Explicit cursor.
Implicit Cursor- Managed by PL/SQL engine
When any DML statement including select statement returning single row is executed in PL/SQL program and programmer has not assigned an explicit cursor (pointer) for that DML statement then PL/SQL assigns an implicit cursor to it and controls its life cycle, so programmer does not have any control over it.Programmer does not have control over life cycle of implicit cursor(cannot perform OPEN, FECT and CLOSE operation), however for each SQL DML statements (INSERT, UPDATE, DELETE and one row returning SELECT) that database server executes opens an implicit cursor called "SQL" and attributes associated with it can be used to get information about the most recently executed SQL statement. The SQL cursor has the four attributes :
- SQL%FOUND - returns true if UPDATE, DELETE, or INSERT affected at least one record. And returns true for SELECT only when it returns only one row, else false.
- SQL%NOTFOUND- For UPDATE, DELETE, or INSERT statements it is the opposite of %FOUND.
- SQL%ROWCOUNT - If RDBMS has opened a SQL cursor in current session then return TRUE else NULL. See following example for better understanding.
- SQL%ISOPEN - Always return false because for all DML statements the implicit cursor will already have been opened and closed implicitly by PL/SQL.
2. When a SELECT statement is executed and it returns single row, here programmer has a choice to use implicit or explicit cursor. It is recommended that always use explicit cursor for select statement even for single row query. (Why? - Read point# 3).
3. If an implicit SELECT statement returns more than one row, it raises the TOO_MANY_ROWS exception and current block execution terminates and control reaches in exception block.
Now lets write a sample PL/SQL program and summarise implicit cursor understanding and familiarise with implicit cursor "SQL" attributes handling:- Execute the following PL/SQL program in SQLPLUS or SQL developer. How to execute PL/SQL program in SQL*PLUS or SQL developer?
set serveroutput on DECLARE v_orgId NUMBER(3) := 90; BEGIN Insert into HR.EMPLOYEES (EMPLOYEE_ID,FIRST_NAME,LAST_NAME,EMAIL,PHONE_NUMBER, HIRE_DATE,JOB_ID,SALARY,COMMISSION_PCT,MANAGER_ID,DEPARTMENT_ID) values (007,'NIKHIL','RANJAN','NIKSR','515.123.4568', to_date('21-SEP-11','DD-MON-RR'),'AD_VP',17000,null,100,90);-- if commit is enabled , SQL%FOUND will return false, since SQL cursor is closed -- However, SQL%ROWCOUNT will be True since , cursor was opened in this session --commit; ---inserted a row so, SQL cursor open for it implicitly IF SQL%FOUND THEN -- affected at least one row DBMS_OUTPUT.PUT_LINE('Yes, one row inserted successfully!!'); ELSE DBMS_OUTPUT.PUT_LINE('No,insert failed!'); END IF; update HR.EMPLOYEES set salary = salary * 1.2 where Department_ID = v_orgId; -- if commit is enabled , SQL%FOUND will return false, since SQL cursor closed -- However, SQL%ROWCOUNT will be True since , cursor was opened in this session --commit; ---Updated rows so, SQL cursor open for it implicitly IF SQL%FOUND THEN -- affected at least one row DBMS_OUTPUT.PUT_LINE('Yes,rows updated successfully!!'); ELSE DBMS_OUTPUT.PUT_LINE('No,updated occurred!'); END IF; --SQL Cursor is opened, it returns TRUE else NULL IF SQL%ROWCOUNT IS NULL THEN -- affected at least one row DBMS_OUTPUT.PUT_LINE('SQL cursor not opened!!'); ELSE DBMS_OUTPUT.PUT_LINE('SQL cursor opened!!'); END IF; END; /
=========Sample output==============
SQL> @cursor_1.sql
Yes, one row inserted successfully!!
Yes,rows updated successfully!!
SQL cursor opened!!
PL/SQL procedure successfully completed.
==================================
In above program, an insert statement is executed and check for SQL%FOUND returns true and display output accordingly. Similarly, when an update query is executed, it will updated multiple rows in database so, check of SQL%FOUND returns true. Finally,when check for SQL%ROWCOUNT
is done it also return true since SQL cursor has been opened in this session(for Insert and Update).Please take a note of following points about above program.
- When commit is enabled in above program, SQL%FOUND returns false in both Insert and Update check because after commit SQL cursor has flushed its attributes however, SQL%ROWCOUNT still return true because cursor was opened in this session.
- When SQL%ROWCOUNT will give NULL, Just comment Insert and Update statements and run this program again in new session, you will get NULL this time because no SQL cursor was opened for any SQL DML statements.
Explicit cursor - a reference/pointer to SELECT statement
An explicit cursor is a SELECT statement that is explicitly defined in the declaration section of our PL/SQL program and that select stament is assigned a name. Explicit cursor is not possible for UPDATE, DELETE, and INSERT statements, as stated in implicit cursor section.Explicit cursor is only for SELECT statement, No explicit cursor for UPDATE, DELETE, and INSERT statements.Do we really need explicit cursor for update,delete and insert ?- No, attributes associated with implicit cursor "SQL" has sufficient information to understand whether these operation has been performed of not, as we saw in previous sample example.
With explicit cursor programmer has complete control over state of cursor and its attributes like FOUND, NOTFOUND, ISOPEN and ROWCOUNT gives information for efficient cursor processing. Let's write a sample program to understand life cycle of cursor and how does PL/SQ Loop can be used to iterate over a cursor.
---Explicit cursor Anonymous program unit DECLARE --Declare a explicit cursor with static SQL and --"employee_cursor_type" is a valid identifier CURSOR employee_cursor_type IS SELECT FIRST_NAME, LAST_NAME, EMAIL FROM HR.EMPLOYEES where Department_ID = 90; v_emplpoyee HR.EMPLOYEES%ROWTYPE; BEGIN --Check whether cursor is open or not IF NOT employee_cursor_type%ISOPEN THEN OPEN employee_cursor_type; -- iterare rows pointed by cursor and -- exit loop when no more record found. LOOP -- FETCH ROWS from cursor until, it reaches end of virtaul table(ResultSet) FETCH employee_cursor_type INTO v_emplpoyee.FIRST_NAME, v_emplpoyee.LAST_NAME,v_emplpoyee.EMAIL; -- Exit when no record found EXIT WHEN employee_cursor_type%NOTFOUND; DBMS_OUTPUT.PUT_LINE ('First name of employee is ' ||v_emplpoyee.FIRST_NAME ||' and email is: '|| v_emplpoyee.EMAIL||'@devinline.com'); END LOOP; END IF; END;
First name of employee is Steven and email is SKING@devinline.com
First name of employee is Neena and email is NKOCHHAR@devinline.com
First name of employee is Lex and email is LDEHAAN@devinline.com
First name of employee is NIKHIL and email is NIKSR@devinline.com
========================================================
In above program, an explicit cursor is declared with a select statement in declaration block along with a variable declaration of Employee row type. Before opening cursor, it is verified that cursor is open or not , if it is not open then open it and fetch rows and assign values into employee row type variable. NOTFOUND attribute of cursor is checked to exit from loop(if no more record is available in result set poined by cursor).
Explicit cursor declaration :- An explicit cursor can be created in various ways in declaration bock. General syntax of cursor declaration is as follows:
Above declaration can be read as, cursor_name is name of cursor, followed by a optional parameter passing which can be used in select statement and an optional return declaration and finally a select statement. For example :
1. Cursor without parameters: Here employee_cur pointing to employees with department_id= 90.
2. Cursor without parameters:- Parameter is passed with cursor pointing to select statement and it can be used to get varied result-set. Here dept_id is passed and it is used to query database.
3. Cursor without return clause:- Return clause specifies what type of rows the cursor pointing. Here, return clause specifies that it will return employees rows.
Properties and constraints with explicit cursor:- CURSOR cursor_name [ ( [ parameter [, parameter ...] ) ] [ RETURN return_specification ] IS SELECT_statement;
1. Cursor without parameters: Here employee_cur pointing to employees with department_id= 90.
--a cursor without parameters. CURSOR employee_cur IS SELECT FIRST_NAME FROM HR.EMPLOYEES where department_id = 90;
--a cursor with parameters. CURSOR employee_cur2 (dept_id_in IN NUMBER) IS SELECT FIRST_NAME FROM HR.EMPLOYEES where department_id = dept_id_in;
--a cursor with return clause. CURSOR employee_cur(dept_id_in IN NUMBER) RETURN employees%ROWTYPE IS SELECT * FROM employees where department_id = dept_id_in;
1. Cursor cannot be used as a variable.It means, it cannot be assigned to another variable and it cannot be assigned any value other than a select statement.
2. SELECT statement pointed by cursor does not necessarily only contain columns of table, it can be a aliased values or modified value too. Generally, column aliases are done when we manipulate column and want to display effective value as column name like following example:
CURSOR employee_cur IS SELECT first_name,email, salary + bonus_var new_salary, /*new_salary is aliased name */ FROM employees WHERE department_id = 90;
DECLARE salary NUMBER := 1000; CURSOR employee_sal_cur IS SELECT salary + salary /*database value is added two times, local variable not used */ FROM employees where first_name= 'Nikhil'; BEGIN OPEN ... FETCH... END;
Note: No error or exception arise, if we do not close cursor. However, in order to avoid unfortunate condition it is good to close cursor after its use.
5. Explicit cursor attributes:- The information about current status of cursor is obtained from cursor attributes.Following table describes them in detail:
Cursor attributes | Description |
---|---|
%FOUND | Returns TRUE if record was fetched successfully, FALSE otherwise. If cursor has not yet been opened, a reference to the %FOUND attribute raises the INVALID_CURSOR exception. |
%NOTFOUND | Returns TRUE if record was not fetched successfully, FALSE otherwise.If cursor has not yet been opened, a reference to the %FOUND attribute raises the INVALID_CURSOR exception. |
%ROWCOUNT | Returns number of records fetched from cursor at that point in time. |
%ISOPEN | Returns TRUE if cursor is open, FALSE otherwise.If cursor is already open , it throws ORA-06511: PL/SQL: cursor already open |
Previous: PL/SQL Record Next: PL/SQL Cursor variable
Tags:
PLSQL_Tutorial
Mua vé tại đại lý vé máy bay Aivivu, tham khảo
ReplyDeletevé máy bay đi Mỹ hạng thương gia
vé máy bay eva từ mỹ về việt nam
lịch bay từ canada về việt nam
bay từ nhật về việt nam
Các chuyến bay từ Incheon về Hà Nội hôm nay
Vé máy bay từ Đài Loan về Việt Nam
giá khách sạn cách ly ở tphcm
Are you searching for the Best Appium Training in Noida? Look no further than APTRON NOIDA! With its exceptional training program and experienced instructors, APTRON NOIDA stands out as the top choice for individuals seeking Appium training in the Noida region. In this article, we will delve into the reasons why APTRON NOIDA is the best place to enhance your Appium skills.
ReplyDelete