Exception Handling in PL/SQL
Last Updated :
28 Apr, 2018
Improve
An exception is an error which disrupts the normal flow of program instructions. PL/SQL provides us the exception block which raises the exception thus helping the programmer to find out the fault and resolve it.
There are two types of exceptions defined in PL/SQL
- User defined exception.
- System defined exceptions.
WHEN exception THEN statement;
DECLARE declarations section; BEGIN executable command(s); EXCEPTION WHEN exception1 THEN statement1; WHEN exception2 THEN statement2; [WHEN others THEN] /* default exception handling code */ END;Note: When other keyword should be used only at the end of the exception handling block as no exception handling part present later will get executed as the control will exit from the block after executing the WHEN OTHERS.
- System defined exceptions:
These exceptions are predefined in PL/SQL which get raised WHEN certain database rule is violated.
System-defined exceptions are further divided into two categories:
- Named system exceptions.
- Unnamed system exceptions.
- Named system exceptions: They have a predefined name by the system like ACCESS_INTO_NULL, DUP_VAL_ON_INDEX, LOGIN_DENIED etc. the list is quite big.
So we will discuss some of the most commonly used exceptions:
Lets create a table geeks.
create table geeks(g_id int , g_name varchar(20), marks int); insert into geeks values(1, 'Suraj',100); insert into geeks values(2, 'Praveen',97); insert into geeks values(3, 'Jessie', 99);
- NO_DATA_FOUND: It is raised WHEN a SELECT INTO statement returns no rows. For eg:
SQL DECLARE temp varchar(20); BEGIN SELECT g_id into temp from geeks where g_name='GeeksforGeeks'; exception WHEN no_data_found THEN dbms_output.put_line('ERROR'); dbms_output.put_line('there is no name as'); dbms_output.put_line('GeeksforGeeks in geeks table'); end;
ERROR there is no name as GeeksforGeeks in geeks table
- TOO_MANY_ROWS:It is raised WHEN a SELECT INTO statement returns more than one row.
SQL DECLARE temp varchar(20); BEGIN -- raises an exception as SELECT -- into trying to return too many rows SELECT g_name into temp from geeks; dbms_output.put_line(temp); EXCEPTION WHEN too_many_rows THEN dbms_output.put_line('error trying to SELECT too many rows'); end;
error trying to SELECT too many rows
- VALUE_ERROR:This error is raised WHEN a statement is executed that resulted in an arithmetic, numeric, string, conversion, or constraint error. This error mainly results from programmer error or invalid data input.
SQL DECLARE temp number; BEGIN SELECT g_name into temp from geeks where g_name='Suraj'; dbms_output.put_line('the g_name is '||temp); EXCEPTION WHEN value_error THEN dbms_output.put_line('Error'); dbms_output.put_line('Change data type of temp to varchar(20)'); END;
Error Change data type of temp to varchar(20)
- ZERO_DIVIDE = raises exception WHEN dividing with zero.
SQL DECLARE a int:=10; b int:=0; answer int; BEGIN answer:=a/b; dbms_output.put_line('the result after division is'||answer); exception WHEN zero_divide THEN dbms_output.put_line('dividing by zero please check the values again'); dbms_output.put_line('the value of a is '||a); dbms_output.put_line('the value of b is '||b); END;
dividing by zero please check the values again the value of a is 10 the value of b is 0
- NO_DATA_FOUND: It is raised WHEN a SELECT INTO statement returns no rows. For eg:
- Unnamed system exceptions:Oracle doesn't provide name for some system exceptions called unnamed system exceptions.These exceptions don't occur frequently.These exceptions have two parts code and an associated message.
The way to handle to these exceptions is to assign name to them using Pragma EXCEPTION_INIT
Syntax:
PRAGMA EXCEPTION_INIT(exception_name, -error_number);
error_number are pre-defined and have negative integer range from -20000 to -20999. Example:SQL DECLARE exp exception; pragma exception_init (exp, -20015); n int:=10; BEGIN FOR i IN 1..n LOOP dbms_output.put_line(i*i); IF i*i=36 THEN RAISE exp; END IF; END LOOP; EXCEPTION WHEN exp THEN dbms_output.put_line('Welcome to GeeksforGeeks'); END;
1 4 9 16 25 36 Welcome to GeeksforGeeks
- User defined exceptions:
This type of users can create their own exceptions according to the need and to raise these exceptions explicitly raise command is used.
Example:
- Divide non-negative integer x by y such that the result is greater than or equal to 1.
From the given question we can conclude that there exist two exceptions
- Division be zero.
- If result is greater than or equal to 1 means y is less than or equal to x.
SQL DECLARE x int:=&x; /*taking value at run time*/ y int:=&y; div_r float; exp1 EXCEPTION; exp2 EXCEPTION; BEGIN IF y=0 then raise exp1; ELSEIF y > x then raise exp2; ELSE div_r:= x / y; dbms_output.put_line('the result is '||div_r); END IF; EXCEPTION WHEN exp1 THEN dbms_output.put_line('Error'); dbms_output.put_line('division by zero not allowed'); WHEN exp2 THEN dbms_output.put_line('Error'); dbms_output.put_line('y is greater than x please check the input'); END;
Input 1: x = 20 y = 10 Output: the result is 2
Input 2: x = 20 y = 0 Output: Error division by zero not allowed
Input 3: x=20 y = 30 Output:<.em> Error y is greater than x please check the input
RAISE_APPLICATION_ERROR: It is used to display user-defined error messages with error number whose range is in between -20000 and -20999. When RAISE_APPLICATION_ERROR executes it returns error message and error code which looks same as Oracle built-in error. Example:SQL DECLARE myex EXCEPTION; n NUMBER :=10; BEGIN FOR i IN 1..n LOOP dbms_output.put_line(i*i); IF i*i=36 THEN RAISE myex; END IF; END LOOP; EXCEPTION WHEN myex THEN RAISE_APPLICATION_ERROR(-20015, 'Welcome to GeeksForGeeks'); END;
Error report: ORA-20015: Welcome to GeeksForGeeks ORA-06512: at line 13 1 4 9 16 25 36
Note: The output is based on Oracle Sql developer, the output order might change IF you're running this code somewhere else. Scope rules in exception handling:- We can't DECLARE an exception twice but we can DECLARE the same exception in two dIFferent blocks.
- Exceptions DECLAREd inside a block are local to that block and global to all its sub-blocks.
SQL DECLARE GeeksforGeeks EXCEPTION; age NUMBER:=16; BEGIN -- sub-block BEGINs DECLARE -- this declaration prevails GeeksforGeeks EXCEPTION; age NUMBER:=22; BEGIN IF age > 16 THEN RAISE GeeksforGeeks; /* this is not handled*/ END IF; END; -- sub-block ends EXCEPTION -- Does not handle raised exception WHEN GeeksforGeeks THEN DBMS_OUTPUT.PUT_LINE ('Handling GeeksforGeeks exception.'); WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE ('Could not recognize exception GeeksforGeeks in this scope.'); END;
Could not recognize exception GeeksforGeeks in this scope.
- Divide non-negative integer x by y such that the result is greater than or equal to 1.
From the given question we can conclude that there exist two exceptions
- Exception handling is very useful for error handling, without it we have to issue the command at every point to check for execution errors:
Example:
Select .. .. check for 'no data found' error Select .. .. check for 'no data found' error Select .. .. check for 'no data found' error
Here we can see that it is not robust as error processing is not separated from normal processing and IF we miss some line in the code than it may lead to some other kind of error. - With exception handling we handle errors without writing statements multiple times and we can even handle dIFferent types of errors in one exception block:
Example:
BEGIN SELECT ... SELECT ... SELECT ... . . . exception WHEN NO_DATA_FOUND THEN /* catches all 'no data found' errors */ ... WHEN ZERO_DIVIDE THEN /* different types of */ WHEN value_error THEN /* errors handled in same block */ ...
- Improves readability by letting us isolate error-handling routines and thus providing robustness.
- Provides reliability, instead of checking for dIFferent types of errors at every point we can simply write them in exception block and IF error exists exception will be raised thus helping the programmer to find out the type of error and eventually resolve it.