Cursors and Exception Handling:
 
															Cursors and Exception Handling:
5.1 Concepts of Cursors
 5.1.1 Types of cursors (Implicit & Explicit )
 5.1.2 Declare, open, fetch and close cursors.
 5.2 Cursor Attributes :
(%FOUND,%NOTFOUND,
%ISOPEN,%ROWCOUNT)
 5.3 Exception Handling in PL/SQL
 5.3.1 Types of Exceptions:
 5.3.1.1 Named System Exceptions
 5.3.1.2 Unnamed System
 Exceptions
 5.3.1.3 User-defined Exceptions
 5.3.1.4 User Defined Exceptions
 5.3.2 Exception Handling
				Cursors and Exception Handling in PL/SQL.
5.1 Concepts of Cursors.
- A cursor in PL/SQL is a mechanism that allows processing multiple rows from a query one row at a time.
- Since SQL queries return a result set, cursors help in handling this data efficiently within PL/SQL blocks.
PL/SQL provides two types of cursors:
- Implicit Cursors – Automatically created by Oracle for- SELECT,- INSERT,- UPDATE, or- DELETEstatements.
- Explicit Cursors – Manually defined by the programmer to process multiple rows from a query.
5.1.1 Types of Cursors.
1. Implicit Cursors.
- Created automatically when a SQL statement executes inside PL/SQL.
- Used for- INSERT,- UPDATE,- DELETE, and- SELECT...INTOstatements.
- No need for explicit declaration, opening, or closing.
- Useful when a query returns only one row.
Example of Implicit Cursor:
DECLARE
   emp_name employees.name%TYPE;
BEGIN
   SELECT name INTO emp_name FROM employees WHERE emp_id = 101;
   DBMS_OUTPUT.PUT_LINE('Employee Name: ' || emp_name);
END;
/				- Here, Oracle creates an implicit cursor for the- SELECTstatement.
- The cursor automatically fetches the data and closes itself.
2. Explicit Cursors.
- Used when a query returns multiple rows.
- Must be declared, opened, fetched, and closed explicitly.
- Provides more control over data retrieval.
Example of Explicit Cursor:
DECLARE
   CURSOR emp_cursor IS SELECT name FROM employees;
   emp_name employees.name%TYPE;
BEGIN
   OPEN emp_cursor;
   FETCH emp_cursor INTO emp_name;
   DBMS_OUTPUT.PUT_LINE('Employee Name: ' || emp_name);
   CLOSE emp_cursor;
END;
/				- Here, an explicit cursor is created for fetching employee names.
- The cursor is manually opened, fetched, and closed.
5.1.2 Cursor Operations (Declare, Open, Fetch, Close)
1. Declaring a Cursor.
- A cursor is declared to store a result set of a SQL query.
- Declared in the DECLARE section using the- CURSORkeyword.
- Syntax:
CURSOR cursor_name IS query;
Example:
CURSOR emp_cursor IS SELECT name, salary FROM employees WHERE department = 'IT';
2. Opening a Cursor.
- The- OPENstatement allocates memory and executes the query.
- It does not fetch data yet.
- SYNTAX
OPEN cursor_name;
Example:
OPEN emp_cursor;
3. Fetching Data from Cursor.
- The- FETCHstatement retrieves one row at a time.
- Each- FETCHmoves the cursor to the next row.
- SYNTAX
FETCH cursor_name INTO variable1, variable2, ...;
Example:
FETCH emp_cursor INTO emp_name, emp_salary;
4. Closing a Cursor.
- The- CLOSEstatement releases memory used by the cursor.
- SYNTAX
CLOSE cursor_name;
Example:
CLOSE emp_cursor;
5.2 Cursor Attributes.
| Cursor Attribute | Description | 
|---|---|
| %FOUND | Returns TRUE if the last fetch retrieved a row. | 
| %NOTFOUND | Returns TRUE if the last fetch failed (no rows left). | 
| %ISOPEN | Returns TRUE if the cursor is open. | 
| %ROWCOUNT | Returns the number of rows fetched so far. | 
1. %FOUND Attribute.
- Used to check if a row was successfully fetched.
- Example :-
DECLARE
   CURSOR emp_cursor IS SELECT name FROM employees;
   emp_name employees.name%TYPE;
BEGIN
   OPEN emp_cursor;
   FETCH emp_cursor INTO emp_name;
   
   IF emp_cursor%FOUND THEN
      DBMS_OUTPUT.PUT_LINE('Data found: ' || emp_name);
   ELSE
      DBMS_OUTPUT.PUT_LINE('No data found');
   END IF;
   CLOSE emp_cursor;
END;
/				2. %NOTFOUND Attribute
- Used to check if no more rows exist in the result set.
DECLARE
   CURSOR emp_cursor IS SELECT name FROM employees;
   emp_name employees.name%TYPE;
BEGIN
   OPEN emp_cursor;
   FETCH emp_cursor INTO emp_name;
   
   IF emp_cursor%NOTFOUND THEN
      DBMS_OUTPUT.PUT_LINE('No more records');
   ELSE
      DBMS_OUTPUT.PUT_LINE('Employee: ' || emp_name);
   END IF;
   
   CLOSE emp_cursor;
END;
/				3. %ISOPEN Attribute
- Checks whether the cursor is open or closed.
DECLARE
   CURSOR emp_cursor IS SELECT name FROM employees;
BEGIN
   OPEN emp_cursor;
   
   IF emp_cursor%ISOPEN THEN
      DBMS_OUTPUT.PUT_LINE('Cursor is open');
   END IF;
   
   CLOSE emp_cursor;
END;
/				4. %ROWCOUNT Attribute.
- Returns number of rows fetched so far.
DECLARE
   CURSOR emp_cursor IS SELECT name FROM employees;
   emp_name employees.name%TYPE;
BEGIN
   OPEN emp_cursor;
   
   LOOP
      FETCH emp_cursor INTO emp_name;
      EXIT WHEN emp_cursor%NOTFOUND;
      
      DBMS_OUTPUT.PUT_LINE('Row ' || emp_cursor%ROWCOUNT || ': ' || emp_name);
   END LOOP;
   
   CLOSE emp_cursor;
END;
/				5.3 Exception Handling in PL/SQL.
- Exception handling in PL/SQL allows developers to detect and manage errors that occur during program execution.
- It ensures that errors are properly handled without abruptly terminating the execution of a PL/SQL block.
- When an error occurs, PL/SQL raises an exception, which can be handled using the- EXCEPTIONblock.
- Exceptions can be predefined (system-generated) or user-defined.
5.3.1 Types of Exceptions
PL/SQL provides three types of exceptions:
- Named System Exceptions (Predefined by Oracle)
- Unnamed System Exceptions (Raised by the system but not predefined)
- User-Defined Exceptions (Custom exceptions created by the programmer)
5.3.1.1 Named System Exceptions
- Oracle provides predefined exceptions for common errors like division by zero or invalid operations.
- These exceptions do not need explicit declaration.
| Exception Name | Error Code | Description | 
|---|---|---|
| NO_DATA_FOUND | ORA-01403 | Raised when a SELECT INTO statement returns no rows. | 
| TOO_MANY_ROWS | ORA-01422 | Raised when a SELECT INTO statement returns more than one row. | 
| ZERO_DIVIDE | ORA-01476 | Raised when attempting to divide a number by zero. | 
| INVALID_NUMBER | ORA-01722 | Raised when an invalid number is used in an arithmetic operation. | 
DECLARE
   v_result NUMBER;
BEGIN
   v_result := 10 / 0; -- This will cause a division by zero error
EXCEPTION
   WHEN ZERO_DIVIDE THEN
      DBMS_OUTPUT.PUT_LINE('Error: Division by zero is not allowed');
END;
/
The ZERO_DIVIDE exception is automatically raised and handled in the EXCEPTION block.
5.3.1.2 Unnamed System Exceptions.
- Some exceptions are raised by the system but do not have predefined names.
- These can be handled using the- WHEN OTHERSclause or by associating them with a custom name using PRAGMA EXCEPTION_INIT.
- Example.
DECLARE
   v_salary NUMBER;
BEGIN
   SELECT salary INTO v_salary FROM employees WHERE emp_id = 9999; -- Invalid ID
EXCEPTION
   WHEN OTHERS THEN
      DBMS_OUTPUT.PUT_LINE('An error occurred: ' || SQLERRM);
END;
/				- The- WHEN OTHERSclause catches any unnamed system exception.
- SQLERRMretrieves the error message.
User-Defined Exceptions.
- User-defined exceptions allow developers to define custom error conditions that are not automatically handled by the system.
To create a user-defined exception, follow these steps:
- Declare the exception in the- DECLAREsection.
- Raise the exception using the- RAISEstatement.
- Handle the exception in the- EXCEPTIONblock.
DECLARE
   insufficient_funds EXCEPTION;  -- Step 1: Declare exception
   v_balance NUMBER := 500;
   v_withdraw_amount NUMBER := 1000;
BEGIN
   IF v_withdraw_amount > v_balance THEN
      RAISE insufficient_funds;  -- Step 2: Raise exception
   END IF;
   
   v_balance := v_balance - v_withdraw_amount;
   
EXCEPTION
   WHEN insufficient_funds THEN
      DBMS_OUTPUT.PUT_LINE('Error: Insufficient funds in the account.');
END;
/				Exception Handling in PL/SQL.
- PL/SQL handles exceptions using the- EXCEPTIONblock, which consists of- WHENclauses to catch specific exceptions.
- Syntax.
BEGIN
   -- Executable statements
EXCEPTION
   WHEN exception_name1 THEN
      -- Exception handling code
   WHEN exception_name2 THEN
      -- Exception handling code
   WHEN OTHERS THEN
      -- Handle all other exceptions
END;
/				EXAMPLE.
DECLARE
   v_result NUMBER;
   v_salary NUMBER;
BEGIN
   v_result := 10 / 0; -- This will cause a division by zero error
   SELECT salary INTO v_salary FROM employees WHERE emp_id = 9999; -- Invalid ID
EXCEPTION
   WHEN ZERO_DIVIDE THEN
      DBMS_OUTPUT.PUT_LINE('Error: Cannot divide by zero.');
   WHEN NO_DATA_FOUND THEN
      DBMS_OUTPUT.PUT_LINE('Error: No record found for given employee ID.');
   WHEN OTHERS THEN
      DBMS_OUTPUT.PUT_LINE('An unexpected error occurred: ' || SQLERRM);
END;
/				Using RAISE_APPLICATION_ERROR
- RAISE_APPLICATION_ERRORis a built-in procedure that allows users to define custom error messages along with an error code (- -20000to- -20999).
EXAMPLE.
DECLARE
   v_balance NUMBER := 500;
   v_withdraw_amount NUMBER := 1000;
BEGIN
   IF v_withdraw_amount > v_balance THEN
      RAISE_APPLICATION_ERROR(-20001, 'Insufficient balance in the account');
   END IF;
   
   v_balance := v_balance - v_withdraw_amount;
END;
/				