Wednesday, October 15, 2014

EXPLAIN TYPES OF CURSORS ?



Cursors are classified depending on the circumstances under which they are opened. If the Oracle engine opened a cursor for its internal processing it is known as an Implicit Cursor. A cursor can also be opened for processing data through a PL/SQL block, on demand. Such a user-defined cursor is known as an Explicit Cursor.

GENERAL CURSOR ATTRIBUTES
When the Oracle engine creates an Implicit or Explicit cursor, cursor control variables are also created to control the execution of the cursor. These are a set of four system variables, which keep track of the Current status of a cursor. These cursor variables can be accessed and used in a PL/SQL code block.

Both Implicit and Explicit cursors have four attributes. They are described below:

Attribute Name
Description
%ISOPEN
Returns TRUE if cursor is open, FALSE otherwise.
%FOUND
Returns TRUE if record was fetched successfully, FALSE otherwise.
%NOTFOUND
Returns TRUE if record was not fetched successfully, FALSE otherwise.
%ROWCOUNT
Returns number of records processed from the cursor.

Implicit Cursor
The Oracle engine implicitly opens a cursor on the Server to process each SQL statement. Since the implicit cursor is opened and managed by the Oracle engine internally, the function of reserving an area in memory, populating this area with appropriate data, processing the data in the memory area, releasing the memory area when the processing is complete is taken care of by the Oracle engine. The resultant data is then passed to the client machine via the network. A cursor is then opened in memory on the client machine to hold the rows returned by the Oracle engine. The number of rows held in the cursor on the client is managed by the client's operating system and it's swap area.
Implicit cursor attributes can be used to access information about the status of the last insert, update, delete or single-row select statements. This can be done by preceding the implicit cursor attribute with the cursor name (i.e. SQL). The values of the cursor attributes always refer to the most recently executed SQL statement, wherever the statement appears. If an attribute value is to be saved for later use, it must be assigned to a (boolean) memory variable.
Implicit Cursor Processing in Client Server Environment

Attribute Name
Description
%ISOPEN
The Oracle engine automatically opens and closes the SQL cursor after executing its associated select, insert, update or delete SQL statement has been processed in case of implicit cursors. Thus the SQL%ISOPEN attribute of an implicit cursor cannot be referenced outside of its SQL statement. As a result, SQL%ISOPEN always evaluates to FALSE.

%FOUND
Evaluates to TRUE, if an insert, update or delete affected one or more rows, or a single-row select returned one or more rows. Otherwise, it evaluates to FALSE. The syntax for accessing this attribute is SQL%FOUND
%NOTFOUND
Is the logical opposite of %FOUND. It evaluates to TRUE, if an insert, update or delete affected no rows, or a single-row select returns no rows. Otherwise, it evaluates to FALSE. The syntax for accessing this attribute is SQL%NOTFOUND
%ROWCOUNT
Returns the number of rows affected by an insert, update or delete, or select into statement. The syntax for accessing this attribute is SQL%ROWCOUNT


Example:
The bank manager has decided to transfer employees across branches. Write a PL/SQL block to accept an employee number and the branch number followed by updating the branch number of that employee to which he belongs appropriately. Display an appropriate message using SQL%FOUND based on the existence of the record in the EMP_MSTR table. Display .an appropriate message using SQL%NOTFOUND based on the non-existence of the record in the EMP_MSTR table.

BEGIN
UPDATE EMP_MSTR SET BRANCH_NO = &BRANCH_NO
WHERE EMP_NO = &EMP_NO;
IF SQL%FOUND THEN
dbms_output.put_line('Employee Successfully Transferred');
END IF;
IF SQL%NOTFOUND THEN
dbms_output.put_line(‘Employee Number does not Exist’);
END IF;
END;

Output:
Enter value for branch_no: 'B4'
OLD  :  UPDATE EMP_MSTR SET BRANCH_NO = &BRANCH_NO
NEW :  UPDATE EMP_MSTR SET BRANCH_NO = 'B4'
Enter value for emp_no: 'El'
OLD :  WHERE EMP_NO = &EMP_NO;
NEW : WHERE EMP_NO = 'El';
Employee Successfully Transferred

PL/SQL procedure successfully completed.

Both SQL%FOUND and SQL%NOTFOUND attributes evaluate to NULL until they are set by an implicit or explicit cursor operation.

Example:
For SQL%ROWCOUNT
The bank manager of Junagadh branch decides to activate all those accounts, which were previously marked as inactive for performing no transactions in last 365 days. Write a PL/SQL block to update the status of accounts. Display an appropriate message based on the number of rows affected by the update fired.

DECLARE
Rows_Affected char(4);
BEGIN
UPDATE ACCT_MSTR SET STATUS = 'A' WHERE STATUS = 'S' AND BRANCH_NO
IN(SELECT BRANCH_NO FROM BRANCH_MSTR
WHERE NAME = ‘Junagadh’);
Rows_Affected := TO_CHAR(SQL%ROWCOUNT);

IF SQL%ROWCOUNT > 0 THEN
dbms_output.put_line(Rows_Affected ||' Account(s) Activated Successfully');
ELSE
dbms_output.put_line('Currently No Inactive Accounts in the Junagadh Branch');
END IF;
END;
Output:
2 Account (s) Activated Successfully
PL/SQL procedure successfully completed.

Explicit Cursor
When individual records in a table have to be processed inside a PL/SQL code block a cursor is used. This cursor will be declared and mapped to an SQL query in the Declare Section of the PL/SQL block and used within its Executable Section. A cursor thus created and used is known as an Explicit Cursor.

Explicit Cursor Management
The steps involved in using an explicit cursor and manipulating data in its active set are:
Ø  Declare a cursor mapped to a SQL select statement that retrieves data for processing
Ø  Open the cursor
Ø  Fetch data from the cursor one row at a time into memory variables
Ø  Process the data held in the memory variables as required using a loop
Ø  Exit from the loop after processing is complete
Ø  Close the cursor

Cursor Declaration
A cursor is defined in the declarative part of a PL/SQL block. This is done by naming the cursor and mapping it to a query. When a cursor is declared, the Oracle engine is informed that a cursor of the said name needs to be opened. The declaration is only an intimation. There is no memory allocation at this point in time. The three commands used to control the cursor subsequently are open, fetch and close.

The Functionality of Open, Fetch And Close Commands
Initialization of a cursor takes place via the open statement, this:
Ø  Defines a private SQL area named after the cursor name
Ø  Executes a query associated with the cursor
Ø  Retrieves table data and populates the named private SQL area in memory i.e. creates the Active Data Set
Ø  Sets the cursor row pointer in the Active Data Set to the first record

A fetch statement then moves the data held in the Active Data Set into memory variables. Data held in the memory variables can be processed as desired.
The fetch statement is placed inside a Loop ... End Loop construct, which causes the data to be fetched into the memory variables and processed until all the rows in the Active Data Set are processed. The fetch loop then exits. The exiting of the fetch loop is user controlled.
After the fetch loop exits, the cursor must be closed with the close statement. This will release the memory occupied by the cursor and its Active Data Set. A PL/SQL block is necessary to declare a cursor and create an Active Data Set. The cursor name is used to reference the Active Data Set held within the cursor.
Syntax:
CURSOR Cursor_Name IS SELECT statement;
Opening A Cursor
Opening a cursor executes the query and creates the active set that contains all rows, which meet the query search criteria. An open statement retrieves records from a database table and places the records in the cursor (i.e. named private SQL area in memory). A cursor is opened in the Server's memory.
Syntax:
OPEN CursorName;


The working of the Client Tool and Oracle Engine when an explicit cursor is opened using the OPEN command is represented diagrammatically below:

Diagram : Processing of OPEN CURSOR command in the Oracle Engine

Fetching A Record From The Cursor

The fetch statement retrieves the rows from the active set opened in the Server into memory variables declared in the PL/SQL code block on the client one row at a time. The memory variables are opened on the client machine. Each time a fetch is executed, the cursor pointer is advanced to the next row in the Active Data Set.
A standard loop structure (Loop-End Loop) is used to fetch records from the cursor into memory variables one row at a time.

Syntax:
FETCH CursorName INTO Variable 1, Variable2, ..;

There must be a memory variable for each column value of the Active Data Set. Data types must match. These variables will be declared in the DECLARE section of the PL/SQL block.

Closing A Cursor
The close statement disables the cursor and the active set becomes undefined. This will release the memory occupied by the cursor and its Data Set both on the Client and on the Server.
Syntax:
CLOSE CursorName;

Once a cursor is closed, the reopen statement causes the cursor to be reopened.

Explicit Cursor Attributes
Similar to the cursor attributes in case of implicit cursors, four attributes are associated with explicit cursors. The attributes can be used in a PL/SQL code block for processing of data or exiting. The cursor name is appended to the attribute name when referencing the attribute.

Attribute Name
Description
%FOUND
Evaluates to TRUE, if the last fetch succeeded because a row was available, or to FALSE, if the last fetch failed because no more rows were available.
The syntax for accessing this attribute is CursorName%FOUND.
%NOTFOUND
Is the logical opposite of %FOUND. It evaluates to TRUE, if the last fetch has failed because no more rows were available; or to FALSE, if the last fetch returned a row.
The syntax for accessing this attribute is CursorName%NOTFOUND.
%ISOPEN
Evaluates to TRUE, if an explicit cursor is open; or to FALSE, if it is closed. The syntax for accessing this attribute is CursorName%ISOPEN.
%ROWCOUNT
Returns the number of rows fetched from the active set. It is set to zero when the cursor is opened.
The syntax for accessing this attribute is CursorName%ROWCOUNT.

Example:
The bank manager has decided to mark all those accounts as inactive (I) on which there are no transactions performed in the last 365 days. Whenever any such update takes place, a record for the same is maintained in the INACTV_ACCT_MSTR table comprising of the account number, the opening date and the type of account. Write a PL/SQL block to do the same.

Table Name: INACTV_ACCT_MSTR

ACCT_NO
OPNDT
TYPE




Create the table INACTV_ACCT_MSTR as:
CREATE TABLE INACTV_ACCT_MSTR (
ACCT_NO VARCHAR2(10), OPNDT DATE, TYPE VARCHAR2(2));

DECLARE
CURSOR Crsr_NoTrans IS
SELECT ACCT_NO, STATUS, OPNDT, TYPE FROM ACCT_MSTR
WHERE ACCT_NO IN (SELECT ACCT_NO FROM TRANS_MSTR
GROUP BY ACCT_NO HAVING MAX(SYSDATE  - DT) >365);

str_ACCT_NO ACCT_MSTR.ACCT_NO%type;
str_STATUS ACCT_MSTR.STATUS%type;
dt_OPNDT ACCT_MSTR.OPNDT%type;
str_TYPE ACCT_MSTR.TYPE%type;
BEGIN
OPEN Crsr_NoTrans;
IF Crsr_NoTrans%ISOPEN THEN
   LOOP
      FETCH Crsr_NoTrans INTO str_ACCT_NO, str_STATUS, dt_OPNDT, str_TYPE;
      EXIT WHEN Crsr_NoTrans%NOTFOUND;
      IF Crsr_NoTrans%FOUND THEN
UPDATE ACCT_MSTR SET STATUS = 'S'
WHERE ACCT_NO = str_ACCT_NO;
INSERT INTO INACTV_ACCT_MSTR
VALUES(str_ACCT_NO, dt_OPNDT, str_TYPE);
        END IF;
   END LOOP;      .
  COMMIT;
ELSE
dbms_output.put_line ('Unable to open Cursor');
END IF;
CLOSE Crsr_NoTrans;
END;
The above PL/SQL code marks all those accounts as inactive (S) on which there are no transactions performed in the last 365 days. To do this an Explicit cursor named Crsr_NoTrans is declared using the following query:
SELECT ACCT_NO, STATUS, OPNDT, TYPE FROM ACCT_MSTR
WHERE ACCT_NO IN (SELECT ACCT_NO FROM TRANS_MSTR
GROUP BY ACCT_NO HAVING MAX(SYSDATE - DT) >365);
The above query will retrieve account numbers, their status, the date on which the account was opened and the type of account. This information will be retrieved based on the following query:
SELECT ACCT_NO FROM TRANS_MSTR
GROUP BY ACCT_NO HAVING MAX(SYSDATE - DT) >365;
This query is responsible to retrieve only those account numbers from the TRANS_MSTR table where the difference between the current date and the date on which the last transaction was performed is more than 365 days i.e. one year. This means a concept of Subquery is applied here.
Since the above query will retrieve more than one value the following variables are declared to hold them.
str_ACCT_NO ACCT_MSTR.ACCT_NO%type;
str_STATUS ACCT_MSTR.STATUS%type;
dt_OPNDT ACCT_MSTR.OPNDT%type;
str_TYPE ACCT_MSTR.TYPE%type;

The %type here means that the data type of these variables will be as that from the table.

Since the above query may return more than one row a loop is created which is responsible to:
Ø  Fetch the data retrieved by the cursor into the variable
Ø  Check if any data is retrieved
·        Update the STATUS field of the ACCT_MSTR table to reflect the inactivity
·        Insert a record in the INACTV_ACCT_MSTR table to reflect the updation
Ø  Repeat the above steps until the data retrieval process is complete.

Finally a COMMIT is fired to make the changes permanent.

No comments: