PLSQL P
PLSQL P
PL/SQL stands for procedural language-standard query language. It is a significant member of Oracle programming tool set
which is extensively used to code server side programming. Similar to SQL language PL/SQL is also a case-
insensitive programming language.
1.Blocks
Generally a program written in PL/SQL language is divided into blocks. We can say blocks are basic
programming units in PL/SQL programming language.
PL/SQL Blocks contain set of instructions for oracle to execute, display information to the screen, write data to
file, call other programs, manipulate data and many more.
1. Anonymous Block
2. Named Block
Anonymous Block
As the title suggests these anonymous blocks do not have any names as a result they cannot be stored in
database and referenced later.
Named Block
On the other hand Named PL/SQL blocks are the one that have names and are used when creating subroutines
such as procedures, functions and packages. These subroutines then can be stored in the database and
referenced by their name later.
Both type of PL/SQL blocks are further divided into 3 different sections which are:
Declaration Section
This is the first section of PL/SQL block which contains definition of PL/SQL identifiers such as variables,
Constants, cursors and so on. You can say this is the place where all local variables used in the program are
defined and documented.
DECLARE
Var_first_name VARCHAR2(30);
Var_last_name VARCHAR2(30);
Con_flag CONSTANT NUMBER:=0;
The above example shows declaration section of an anonymous block. It begins with keyword declare and
contains two variables var_first_name and var_last_name and one constant con_flag. Notice that semicolon
terminates each declaration.
Execution Section
This section contains executable statements that allow you to manipulate the variables that have been declared
in the declaration section. The content of this section must be complete to allow the block to compile. By
complete I mean complete set of instruction for the PL/SQL engine must be between BEGIN and END
keyword.
The execution Section of any PL/SQL block always begins with the Keyword BEGIN and ends with the
Keyword END.
This is the only mandatory section in PL/SQL block. This section supports all DML commands and
SQL*PLUS built-in functions and using Native Dynamic SQL (NDS) or using DMBS_SQL built-in package it
also supports DDL commands.
BEGIN
SELECT first_name, last_name INTO var_first_name,
var_last_name
FROM employees WHERE employee_id =100;
DBMS_OUTPUT.PUT_LINE
(‘Employee Name ’||var_first_name||’ ‘||var_last_name);
END;
This is very simple program where I fetched the value of first name and last name column from employees
table where employee id is 100 and stored it into the variable var_first_name and var_last_name which we
declared in our first example.
Exception-Handling Section
This is the last section of PL/SQL block which is optional like the declaration block. This section contains
statements that are executed when a runtime error occurs within the block.
Runtime error occurs while the program is running and cannot be detected by the PL/SQL compiler. When a
runtime error occurs, controlled is pass to the exception handling section of the block the error is evaluated and
specific exception is raised.
EXCEPTION
WHEN NO_DATA_FOUND THEN DBMS_OUTPUT.PUT_LINE (‘No Employee Found with ’||
employee_id);
Example : 1
employee_id NUMBER,
first_name VARCHAR2(30),
last_name VARCHAR2(30));
Variable Declaration
All the variable declaration must be done in Declare Section of the PL/SQL block. As soon as you declare a
variable, the compiler will allocate the memory according to the data type to that variable. Though you can
assign value to the variable either in declare section or in execution section of your PL/SQL block but
the declaration must be done in declare section.
10
PL/SQL procedure successfully completed.
This is a very simple program in which I first declared a variable by the name of test_var1 which has data
type number in declaration section and later in execution section I initialized it and assigned a numeric value 10
and then using DBMS_OUTPUT statement I displayed the value of this variable.
Yes in PL/SQL the combo of colon and equal to operator (:=) works as assignment operator which is very
different from the other programming languages.
Variable Initialization
1. Where can we initialize the variables:-
Though it’s mandatory to declare all the variables of your programs in declaration section of your PL/SQL
block but initializing them and assigning them some value in execution section is not mandatory.
You can initialize a variable in declaration section while creating it or you can initialize the variable in
execution section
Variable initialization means assigning some value to the variable which you previously declared. There are
two ways of assigning value to the variable.
First is the direct way of giving value to the variable or assigning value in declaration section(above
example)
DECLARE
var_test1 VARCHAR2(30) := ‘hussain mahammad’; --Declare & initialize the variable at same time
BEGIN
DBMS_OUTPUT.PUT_LINE(var_test1);
END;
hussain mahammad
PL/SQL procedure successfully completed.
Second way is by fetching value from the column of a row of a table and assigning that value to the
variable.
Syntax
SELECT column1, column2…. Column n INTO variable1, variable2… Variable n FROM table_name
WHERE <expression>;
DECLARE
v_salary NUMBER(8);
every variable must be declared prior to its use and we can only declare a variable in declaration section of
PL/SQL block. In the above demonstration I declared a variable by the name of v_salary which has data type
NUMBER and Data width 8.
One thing must take care while declaring variable here is that the data type and data width of your variable and
the column whose value you want to fetch must match.
BEGIN
SELECT salary INTO v_salary FROM employees
WHERE employee_id = 100;
DBMS_OUTPUT.PUT_LINE (v_salary);
END;
This is the execution section of our anonymous block. This section contains our select statement. This select
statement is retrieving salary of the employee whose employee id is 100 from employees table and storing it
into the variable v_salary.
The variable v_salary which we declare above in the declaration section is capable of holding single data at a
time thus make sure your select statement must return only single data. This you can ensure by using WHERE
clause of your SELECT statement as I did in this example.
Let’s put all the parts together and see the complete anonymous block.
24000
PL/SQL procedure successfully completed.
Fetch data from multiple column and store it into multiple variables
Exception-Handling Section:-
This is the last section of PL/SQL block which is optional like the declaration block. This section contains
statements that are executed when a runtime error occurs within the block.
Runtime error occurs while the program is running and cannot be detected by the PL/SQL compiler. When a
runtime error occurs, controlled is pass to the exception handling section of the block the error is evaluated and
specific exception is raised.
We can add below exception if the given employee id is not present in the table then it will execute below
statement
EXCEPTION
WHEN NO_DATA_FOUND THEN DBMS_OUTPUT.PUT_LINE ('No Employee Found with given
employee id');
end;
Syntax
variable_name typed-attribute%type
typed-attribute = tablename.columnname
Where variable name is user defined name given to a variable and type attribute can be anything such as
previously declared PL/SQL variable or column of a table. And at the end %type is the direct reference to the
underlying database object.
NEED OF ANCHORED DATA TYPE :- if we declare a variable with particular data type and size based on
the column that we are going to initialize the value like below example
suppose in future some one has changed the column definition to varchar(40) then we will get error because our
variable data type and column data types will be different. To overcome this issue we will use anchored data
type
5.Constants In PL/SQL:-
Like several other programming languages, the constant in PL/SQL is also a user defined identifier whose
value remains unchanged throughout the program. Like variables in PL/SQL constants also need to be
declared prior to their use. Furthermore you can only declare them in the declaration section of your PL/SQL
block.
Syntax
constant_name CONSTANT datatype (data-width) := value;
First you need to give a valid name to your constant followed by keyword CONSTANT that indicates the
declaration of a constant in your program. Then you have to specify the data type and data width for your
constant followed by the assignment operator and the value which you want to assign to your constant.
Note:-
You must initialize a constant at its declaration. You have to initialize your constant at the time of its creation
in declaration section of your PL/SQL block. You cannot initialize it anywhere else.
Example
This is a simple example of Constant declaration and initialization. Here in declaration section I have declared
a constant v_pi and initialized it with the approximate value of pi. In the execution section we have our DBMS
output statement which is displaying the value stored into our constant.
This is the proper way of declaring and initializing a constant in PL/SQL. We have two more attributes of
PL/SQL constants to discuss which are “DEFAULT” and “NOT NULL”.
DEFAULT
You can use default keyword instead of assignment operator to initialize the constant in PL/SQL. Let’s do an
example and see how to initialize a constant using DEFAULT keyword.
3.141593
PL/SQL procedure successfully completed.
Same code just this time I used keyword DEFAULT instead of assignment operator for initializing the constant
NOT NULL
Next attribute is NOT NULL. Using this attribute you can impose NOT NULL constraint while declaring
constants as well as variables. This will prevent you from assigning NULL values to your constants or
variables.
To impose not null constraint simply write NOT NULL keyword before the Keyword default or before
assignment operator in case you have used it.
3.141593
PL/SQL procedure successfully completed.
NOTE:-
In PL/SQL, you cannot explicitly declare variables as NOT NULL like you can with table columns in SQL.
Variables in PL/SQL are always nullable by default, and there is no direct syntax to enforce the NOT NULL
constraint on variables.
Unlike user variables which can only be declared inside the declaration section of PL/SQL block you can
declare bind variable anywhere in the host environment and that is the reason why we also refer bind variables
as host variable.
[In PL/SQL, bind variables are used to improve the performance, security, and maintainability of SQL statements,
especially when executing them multiple times. Instead of embedding literal values directly in the SQL statement,
bind variables are used to hold the values separately.]
See how easy it is to declare a bind variable in oracle database! You simply have to write a command which starts
with keyword VARIABLE followed by the name of your bind variable which is completely user defined along with
the data type and data width. That’s how we declare a bind variable in Oracle database.
Did you notice that I didn’t write any PL/SQL block or section here to declare this bind variable which is very
unlike the user variable.
Declaring the bind variable is the first use of this variable command there are few other uses of it also. Let’s see
what those are
VARIABLE;
Execute the above command and that will show you the list of all the bind variables that you have declared in your
session.
Let’s do an example and see the definition of this bind variable v_Bind2.
Variable v_bind2;
Execution of above command will show you the definition of bind variable RebellionRider.
This statement starts with keyword Exec which is the starting 4 alphabets of Keyword Execute. You can either
write whole keyword Execute or just the starting 4 alphabets “Exec” both will work fine. This is followed by the
name of our bind variable which is v_bind1. After that we have assignment operator followed by the string
Rebellion Rider, as it’s a string thus it’s enclosed in single quotes.
This is a simple execution block where I initialized the bind variable v_bind1 with the string Manish Sharma.
That is how we initialize the bind variable in Oracle Database or in PL/SQL.
BEGIN
:v_bind1 := ‘RebellionRider’;
DBMS_OUTPUT.PUT_LINE(:v_bind1);
END;
/
1. PUT_LINE is an executable statement which will require the execution section of PL/SQL block for its execution.
In simple words you can only execute this statement in execution section of PL/SQL block otherwise you will get an
error.
2. To see the output returned from this statement you have set the serveroutput on. You can do that by simply writing
and executing
Suppose you want to see the current value of bind variable v_bind1 for that simply write the print command in your
SQL*PLUS
Print :v_bind1;
Or
Print v_bind1;
Writing keyword PRINT without any argument will display you the current values of all the bind variables with
their names in the session.
And this command will set AutoPrint parameter on for the session which will automatically print the values of bind
variable.
[ NORMAL VARIABLES NEED TO BE DECLARE INSIDE DECLARATION SECTION SECTION ONLY,
COMING TO BIND VARIABLE WE CAN DECLARE OUT SIDE OF PL/SQL BLCOK ALSO]
1. IF statements and
2. CASE statements
1. IF THEN
2. IF THEN ELSE
3. IF THEN ELSEIF
CASE statement has 2 different forms such as
IF-THEN Structure
IF condition THEN
Statement1;
…
Statement N;
END IF;
In the starting we have the keyword IF which marks the beginning of IF-THEN block followed by a valid
condition or a valid expression which will get evaluated followed by another keyword THEN. Similarly the
reserved phrase END IF marks the ending of IF-THEN block. In between we have a sequence of executable
statements which will get executed only if the condition evaluated to be true otherwise the whole IF-THEN
block will be skipped.
Working
When an IF-THEN statement is executed a condition is evaluated to either True or False. If the condition
evaluates to true, control is passed to the first executable statement of the IF-THEN construct. If the condition
evaluates to false, control is passed to the first executable statement after the END-IF statement.
Examples:
SET SERVEROUTPUT ON;
DECLARE
v_num NUMBER := 9;
BEGIN
IF v_num < 10 THEN
DBMS_OUTPUT.PUT_LINE(‘Inside The IF’);
END IF;
DBMS_OUTPUT.PUT_LINE(‘outside The IF’);
END;
/
Inside The IF
outside The IF
This is a very simple PL/SQL anonymous block. In the declaration section I have declared a variable v_num with
data type NUMBER and initialized it with integer 9. Let’s come to our execution section. Here as you can see we
have 2 DBMS_OUTPUT statements one is inside the IF-THEN block and another is outside it. The first
DBMS_OUTPUT statement will execute only if the condition of our IF-THEN block is evaluated as true otherwise
it will be skipped but the 2nd DBMS_OUTPUT statement which is outside the IF-THEN block will execute every
time you execute this PL/SQL block.
This means that if the condition is true then both the string INSDIE THE IF and OUTSIDE THE IF will be printed
otherwise only OUTSIDE THE IF will be printed
SET SERVEROUTPUT ON;
DECLARE
V1 VARCHAR(30):= 'MAHAMMAD HUSSAIN';
V2 VARCHAR2(30):= 'WORKS AT TCS';
BEGIN
IF V1 = 'MAHAMMAD HUSSAIN' AND V2 = 'WORKS AT TCS' THEN
DBMS_OUTPUT.PUT_LINE('Everything is Awesome');
END IF;
DBMS_OUTPUT.PUT_LINE('OUT SIDE IF THEN CLAUSE');
END;
/
Everything is Awesome
OUT SIDE IF THEN CLAUSE
This one is slightly different than the previous example. Here we used logical AND operator in the condition. If this
condition is evaluated to be true then both strings from both DBMS_OUTPUT statements will be printed otherwise
only the string from 2nd DBMS_OUTPUT statement will be displayed back to you.
This example is for showing how you can check multiple conditions in a single go using logical operator. You can
even use logical OR instead of logical AND operator.
To overcome this drawback in oracle PL/SQL we have IF-THEN-ELSE statement widely pronounced as IF-ELSE
statement.
With IF-THEN-ELSE in PL/SQL we have two groups of executable statements, one which gets executed if the
condition is evaluated to be true and another group gets executed if the condition is evaluated to be false. Once the
IF-THEN-ELSE construct gets completed the next statement right after IF-THEN-ELSE block is executed.
Syntax
IF condition THEN
Statement 1;
ELSE
Statement 2;
END IF;
Statement 3
In the syntax we can see that IF-THEN-ELSE construct starts with the keyword IF and ends with the reserved phrase
END IF. Followed by IF keyword we have to specify a valid condition which will get evaluated. If this condition is
evaluated to be TRUE then control is passed to the statement 1, and if this condition is evaluated to be false then
control will jump over to statement 2. Once the construct is completed then statement 3 is executed.
Example
Here in this example we will take a numeric input from the user and will check whether a user has entered an even
number or an odd number using IF THEN ELSE statement. This is going to be a very easy example.
'&'
The '&' symbol is used as a substitution variable in PL/SQL. It is mainly used for accepting user input during
runtime. When you use '&' followed by a variable name, PL/SQL prompts the user to enter a value for that
variable when the code is executed. It allows users to provide dynamic input to a program, making it more
interactive
‘MOD’
In PL/SQL, 'mod' is an arithmetic operator used for performing the modulo operation. The syntax is as
follows:
5 IS A ODD NUMBER
IF THEN ELSE Construct complete
PL/SQL procedure successfully completed.
To overcome this we have IF THEN ELSIF condition in Oracle PL/SQL. Using this statement you can check
multiple conditions
Syntax
IF CONDITION 1 THEN
STATEMENT 1;
ELSIF CONDITION 2 THEN
STATEMENT 2;
ELSIF CONDITION 3 THEN
STATEMENT 3;
…
ELSE
STATEMENT N; END IF;
Example
SET SERVEROUTPUT ON;
DECLARE
V_MARKS NUMBER := &PLEASE_ENTER_YOUR_MARKS;
V_GRADE VARCHAR2(30);
BEGIN
IF V_MARKS >=91 THEN
V_GRADE := 'A';
ELSIF V_MARKS >=81 THEN
V_GRADE := 'B';
ELSIF V_MARKS >=71 THEN
V_GRADE := 'C';
ELSIF V_MARKS >=61 THEN
V_GRADE := 'D';
ELSIF V_MARKS >=51 THEN
V_GRADE := 'E';
ELSIF V_MARKS >=35 THEN
V_GRADE := 'F';
END IF;
DBMS_OUTPUT.PUT_LINE('Your grade is: ' || v_GRADE);
END;
/
CASE expression can do all the work of a DECODE expression. Several books recommend using CASE
over DECODE because
As the name suggests it is the simplest version of CASE expression in other words we can say that it is a
flexible and easiest version of DECODE expression.
CASE expression
WHEN value1 THEN result1
WHEN value2 THEN result2
...
ELSE default_result
END
Where
The case expression evaluates the given expression and checks it against each WHEN clause in order. When
a match is found, it returns the corresponding result. If no match is found, it returns the default_result
(optional).
The Simple Case Expression uses search expression to determine the return value. Means simple case
expression evaluates all the input expressions against the search expression. Once a match is found the
corresponding result is returned otherwise Else result is displayed. Furthermore the Else statement is
optional so in case you omit it then Null is displayed when the simple case expression cannot find a match.
Points to remember
The data type of all the input expressions must match with the data type of search expression.
Means data type of search expression and input expression must be the same.
The datatype of all the output results must match with Else result means the data type of output
result along with else result must be the same.
The maximum number of arguments in a CASE expression is 255. All expressions count toward this limit,
including the initial expression of a simple CASE expression and the optional ELSE expression. Each
WHEN … THEN pair counts as two arguments. To avoid exceeding this limit, you can nest CASE
expressions so that the output_result itself is a CASE expression.
Example:
Suppose we have a table "employees" with the columns "employee_id," "first_name," and "salary." We
want to categorize employees based on their salary ranges. We can use a simple case expression to achieve
this:
SELECT
employee_id,
first_name,
salary,
CASE
WHEN salary >= 15000 THEN 'high Earner'
WHEN salary >= 10000 THEN 'Medium Earner'
ELSE 'Low Earner'
END AS salary_category
FROM employees where employee_id between 100 and 150;
CASE
WHEN condition1 THEN result1
WHEN condition2 THEN result2
...
ELSE default_result
END
Here:
condition1, condition2, etc.: These are boolean expressions that are evaluated to true or false.
result1, result2, etc.: These are the values returned when the corresponding condition is true.
default_result (optional): If none of the conditions are true, this value is returned.
Example:
Let's consider a table "employees" with columns "employee_id," "first_name," and "salary." We want to
categorize employees based on their salary ranges into three categories: "High Earner," "Medium Earner,"
and "Low Earner."
SELECT
employee_id,
first_name,
salary,
CASE
WHEN salary >= 100000 THEN 'High Earner'
WHEN salary >= 50000 THEN 'Medium Earner'
ELSE 'Low Earner'
END AS salary_category
FROM employees;
In this example, we use a searched case expression to categorize employees based on their salary. If the
salary is greater than or equal to 100,000, the employee is labeled as "High Earner." If the salary is greater
than or equal to 50,000, the employee is labeled as "Medium Earner." If the salary is below 50,000, the
employee is labeled as "Low Earner."
The output of this query will include the employee details along with the computed "salary_category"
column indicating their respective salary category based on the searched case expression.
Searched case expressions are very flexible as they allow you to specify complex conditions, making them
suitable for various scenarios where you need to evaluate multiple condition
Simple Loop
While Loop
Numeric For Loop and
Cursor For loop
Simple Loop
Simple loop is the most basic loop in Oracle PL/SQL
Syntax
LOOP
Statement 1;
Statement 2;
…
Statement 3;
END LOOP;
Here keyword LOOP marks the beginning and phrase END LOOP marks the ending of the loop. In between we
have a sequence of executable statements.
As you can see in this syntax that unlike conventional loops here we do not have update statements or for that matter
exist conditions which will terminate the loop. May be that is why we call this a simple loop.
In Above syntax as you can see we do not have any exit statement to terminate the loop. This means that if we
execute this program then the execution will keep on printing till we halt it manually.
In this case Oracle PL/SQL gives us two clauses to terminate the loop
1. Exit
2. Exit When
1. Exit
Exit clause will terminate the loop when Exit condition is evaluated to be true. The exit condition is evaluated with
the help of Simple IF THEN condition which we discussed in PL/SQL section 8
19 x 1 = 19
19 x 2 = 38
19 x 3 = 57
19 x 4 = 76
19 x 5 = 95
19 x 6 = 114
19 x 7 = 133
19 x 8 = 152
19 x 9 = 171
19 x 10 = 190
You simply have to add this IF THEN block either right above the phrase END LOOP or immediately below the
keyword loop. What this IF THEN block will do? This block will keep an eye on your counter and will tell the
control to exit the loop when counter either becomes greater than or equal to 10. Which means loop will execute for
10 times.
2. EXIT WHEN
Second way of terminating the loop is by using EXIT WHEN clause. Using this clause you can replace this whole IF
THEN block with a simple single statement.
19 x 1 = 19
19 x 2 = 38
19 x 3 = 57
19 x 4 = 76
19 x 5 = 95
19 x 6 = 114
19 x 7 = 133
19 x 8 = 152
19 x 9 = 171
19 x 10 = 190
Syntax
WHILE condition LOOP
Statement 1;
Statement 2;
…
Statement 3;
END LOOP;
The keyword WHILE marks the beginning of the loop followed by word CONDITION which will serve your test
condition. This will get evaluated either to be true or to be false and at the end of our first line we have another
keyword which is LOOP. The statements 1 through N are sequence of executable statements which define the body
of the loop. And at the end we have a reserved phrase END LOOP which indicates the ending of the while loop.
In order to execute the body of the loop the test condition needs to be true. If this condition is evaluated to be true
then the control will jump inside the loop and execute whatever statements it has. This iteration will continue until
the test condition becomes false. As soon as the test condition is evaluated to be false the control will come out of
the loop and execute the statement which immediately follows the loop.
Examples
SET SERVEROUTPUT ON;
DECLARE
V_NUMBER NUMBER := 0;
V_RESULT NUMBER;
BEGIN
WHILE V_NUMBER <10 LOOP
V_NUMBER := V_NUMBER+1;
V_RESULT := 18*V_NUMBER;
DBMS_OUTPUT.PUT_LINE(18||'X'||V_NUMBER||'='||V_RESULT);
END LOOP;
END;
/
18X1=18
18X2=36
18X3=54
18X4=72
18X5=90
18X6=108
18X7=126
18X8=144
18X9=162
18X10=180
In this example we have declared two variables – V_NUMBER which will serve as a counter and variable
V_RESULT which will hold the result of multiplication.
Down in the execution section we have our while loop. The first statement inside the loop body is an arithmetic
expression which will perform the multiplication of our table and will store the result in V_RESULT variable.
2nd Statement is an output statement which will print the result of the multiplication in a formatted manner.
And the third statement is an update statement which will update the counter with each iteration.
This while loop will keep on iterating until the counter is less than 10. Once the value of the counter becomes 10 the
while loop will terminate and execute the first statement immediately outside the loop body.
1
2
3
4
5
6
7
8
9
10
With the Boolean expression in loop we have to write the code which will change its value to false and terminate the
loop. Failing to do so can make your loop an infinity loop. In the above program the simple IF THEN block inside
the loop body will change the value of the Boolean expression V_TEST and set it on false when V_NUMBER
becomes equal to 10 this will terminate the loop and bring the V_NUMBER over the first statement immediately
outside the loop body.
17X1=17
17X2=34
17X3=51
17X4=68
17X5=85
17X6=102
17X7=119
17X8=136
17X9=153
17X10=170
Syntax
FOR loop_counter IN [REVERSE] lower_bound..upper_bound LOOP
-- Loop body statements
END LOOP;
Counter Variable: The loop_counter variable is used to control the iteration of the loop. It is automatically initialized
to the lower_bound value and increments (or decrements, if the loop is defined as REVERSE) by 1 in each iteration.
The loop terminates when the loop_counter reaches the upper_bound.
Loop Range: The lower_bound and upper_bound define the range of values that the loop counter will take. The loop
will execute the loop body statements for each value of the loop counter within this range.
REVERSE Keyword: The optional REVERSE keyword can be used to execute the FOR loop in the reverse
direction (i.e., from upper_bound to lower_bound).
1
2
3
4
5
6
7
8
9
10
Here we only have the execution section and inside that we have our FOR loop which will print the value of
v_counter variable from 1 to 10.
Have you noticed that we didn’t declare the v_counter variable anywhere in the program? Even we don’t have the
declaration section here in this code. This is because variable v_counter is an implicit index integer variable which
gets declared automatically with the definition of FOR loop. Moreover the variable v_counter will increment by 1
with each iteration automatically by FOR loop construct thus you do not need to write update statement
(v_counter := v_counter +1) explicitly. As a matter of fact if you will try to write the update statement in the “FOR
loop” then you will get an error.
BEGIN
FOR v_counter IN REVERSE 1..10 LOOP
DBMS_OUTPUT.PUT_LINE(v_counter);
END LOOP;
END;
/
10
9
8
7
6
5
4
3
2
1
16X1=16
16X2=32
16X3=48
16X4=64
16X5=80
16X6=96
16X7=112
16X8=128
16X9=144
16X10=160
In this example we need one extra variable to store the result of the multiplication thus we declared a variable
V_RESULT with NUMBER data type. In the execution section we have our “FOR loop” and this time inside the
loop we have only two statements. First is an arithmetic expression which will perform the multiplication of our
table and will store the result in V_RESULT variable. Second is the output statement which will display you the
result in a formatted manner.
14.Database Triggers In PL/SQL
Triggers are named PL/SQL blocks which are stored in the database. We can also say that they are specialized
stored programs which execute implicitly when a triggering event occurs. This means we cannot call and execute
them directly instead they only get triggered by events in the database.
1. A DML Statement – An Update, Insert or Delete statement executing on any table of your database. You can
program your trigger to execute either BEFORE or AFTER executing your DML statement. For example, you can
create a trigger which will get fired Before the Update. Similarly, you can create a trigger which will get triggered
after the execution of your INSERT DML statement.
2. A DDL Statement – Next type of triggering statement can be a DDL Statement such as CREATE or ALTER. These
triggers can also be executed either BEFORE or AFTER the execution of your DDL statement. These triggers are
generally used by DBAs for auditing purposes. And they really come in handy when you want to keep an eye on the
various changes on your schema. For instance, who created the object or which user. Just like some cool spy tricks.
3. A system event. – Yes, you can create a trigger on a system event. And by a system event, I mean shut down or
startup of your database.
4. A User Events – Another type of triggering event can be User Events such as log off or log on onto your database.
You can create a trigger which will either execute before or after the event. Furthermore, it will record the
information such as time of event occur, the username who created it.
As the name suggests these are the triggers which depend on DML statements such as Update, Insert or Delete. They
get fired either before or after them. Using DML trigger you can control the behavior of your DML statements. You
can audit, check, replace or save values before they are changed. Automatic Increment of your Numeric primary key
is one of the most frequent tasks of these types of triggers.
Again as the name suggests these are the type of triggers which are created over DDL statements such as CREATE
or ALTER. They get fired either before or after the execution of your DDL statements. Using this type of trigger you
can monitor the behavior and force rules on your DDL statements.
3. System or Database Event triggers.
Third type of triggers is system or database triggers. These are the type of triggers which come into action when
some system event occurs such as database log on or log off. You can use these triggers for auditing purposes. For
example, keeping an eye on information of system access like say who connects with your database and when. Most
of the time System or Database Event triggers work as Swiss Knife for DBAs and help them in increasing the
security of the data.
4. Instead-of Trigger
This is a type of trigger which enables you to stop and redirect the performance of a DML statement. Often this type
of trigger helps you in managing the way you write to non-updatable views. You can also see the application of
business rules by INSTEAD OF triggers where they insert, update or delete rows directly in tables that are defining
updatable views. Alternatively, sometimes the INSTEAD OF triggers are also seen inserting, updating or deleting
rows in designated tables that are otherwise unrelated to the view.
5. Compound triggers
These are multi-tasking triggers that act as both statement as well as row-level triggers when the data is inserted,
updated or deleted from a table. You can capture information at four timing points using this trigger:
Syntax
CREATE [OR REPLACE] TRIGGER Ttrigger_name
{BEFORE|AFTER} Triggering_event ON table_name
[FOR EACH ROW]
[FOLLOWS another_trigger_name]
[ENABLE/DISABLE]
[WHEN condition]
DECLARE
declaration statements
BEGIN
executable statements
EXCEPTION
exception-handling statements
END;
Examples
In order to demonstrate the creation process of DML trigger we need to first create a table.
I have created this table with the name SUPERHEROES which has only one column sh_name with data type
varchar2 and data width 15. Now I will write a DML trigger which will work on this table.
So the table is created. Now let’s do some examples which will help you in understanding the concepts more clearly.
1 row inserted.
Above three examples showed you 3 different triggers for 3 different DML events on one table. Don’t you think that
if we can cover all these 3 events in just 1 trigger then it will be a great relief? If you think so then my dear friend I
have some good news for you. Let me show you how we can achieve this feat.
In PL/SQL, Data Definition Language (DDL) triggers are used to respond to changes in the database
schema. These triggers are fired automatically when specific DDL statements (e.g., CREATE, ALTER,
DROP) are executed. DDL triggers allow developers to define custom actions that should be taken before
or after DDL statements, such as deleting, inserting, or updating keywords.
Here's a brief overview of how you can handle deleting, inserting, or updating keywords in DDL triggers:
1. Deleting Keywords:
When a DDL trigger is fired due to a DELETE operation on a database object (e.g., dropping a table), you
can use the trigger to perform specific actions before or after the deletion. For instance, you might want to
log the event, prevent certain objects from being deleted, or perform additional cleanup tasks before the
object is removed from the schema.
2. Inserting Keywords:
If a DDL trigger is triggered by an INSERT operation on a database object (e.g., creating a new table or
index), you can utilize the trigger to perform actions related to the newly created object. For example, you
could set default values for specific columns, apply naming conventions, or grant permissions to certain
users after the object is created.
3. Updating Keywords:
When a DDL trigger is invoked by an UPDATE operation on a database object (e.g., modifying a table's
structure), you can leverage the trigger to carry out tasks before or after the update. For instance, you
might want to enforce specific constraints, synchronize related objects, or log the changes made during the
update process.
It's important to note that while DDL triggers can be powerful tools for managing database schema
changes, they should be used judiciously. Careful consideration of the potential impact on the database
and the necessity of the triggered actions is essential to avoid unintended consequences.
Example 4: INSERT, UPDATE, DELETE All in One DML Trigger Using IF-THEN-
ELSIF
CREATE OR REPLACE TRIGGER tr_superheroes
BEFORE INSERT OR DELETE OR UPDATE ON superheroes
FOR EACH ROW
ENABLE
DECLARE
v_user VARCHAR2(15);
BEGIN
SELECT
user INTO v_user FROM dual;
IF INSERTING THEN
DBMS_OUTPUT.PUT_LINE('one line inserted by '||v_user);
ELSIF DELETING THEN
DBMS_OUTPUT.PUT_LINE('one line Deleted by '||v_user);
ELSIF UPDATING THEN
DBMS_OUTPUT.PUT_LINE('one line Updated by '||v_user);
END IF;
END;
/
Using this one trigger you can achieve the same results as that of the above three triggers.
EXAMPLE:-
CREATE TABLE VEHICLES_LOGS(
LOG_USER VARCHAR2(30),
LOG_MESSAGE VARCHAR(30),
LOG_DATE DATE);
TRIGGER 1
SET SERVEROUTPUT ON;
CREATE OR REPLACE TRIGGER before_insert_trigger
BEFORE INSERT ON VEHICLES
FOR EACH ROW
BEGIN
INSERT INTO VEHICLES_LOGS(LOG_USER, LOG_MESSAGE, LOG_DATE)
VALUES(USER, 'Vehicles log updated before insert', SYSTIMESTAMP);
END;
/
TRIGGER 2
SET SERVEROUTPUT ON;
CREATE OR REPLACE TRIGGER after_insert_trigger
AFTER INSERT ON VEHICLES
FOR EACH ROW
BEGIN
INSERT INTO VEHICLES_LOGS(LOG_USER, LOG_MESSAGE, LOG_DATE)
VALUES(USER, 'Vehicles log updated After insert', SYSTIMESTAMP);
END;
/
When ever we insert a new row both the triggeres get fired and we can see the data in VEHICLES_LOG table.
NEW:
The NEW keyword represents the new values that will be inserted or updated into the table after the DML
operation.
In an INSERT trigger, the NEW keyword refers to the values being inserted into the table.
In an UPDATE trigger, the NEW keyword represents the new values that will replace the existing
values in the table.
In a DELETE trigger, the NEW keyword is not applicable since there are no new values being
added.
OLD:
The OLD keyword represents the existing values of the rows before the DML operation.
In an UPDATE trigger, the OLD keyword refers to the old values that are currently in the table,
before any updates take place.
In a DELETE trigger, the OLD keyword represents the values that are being removed from the
table.
In an INSERT trigger, the OLD keyword is not applicable since there are no old values.
By using the NEW and OLD keywords in triggers, you can perform actions based on the values of the
affected rows before and after a DML operation. These keywords add flexibility and control to your
trigger logic, allowing you to enforce business rules, perform audits, and take various actions based on
the data changes.
:NEW
->INSERT
SET SERVEROUTPUT ON;
CREATE OR REPLACE TRIGGER VEHICLES_TABLE_AUDIT
AFTER INSERT ON VEHICLES
FOR EACH ROW
BEGIN
INSERT INTO VEHICLES_AUDIT_LOG (USER_NAME, NEW_V_NAME, NEW_V_AGE,
TIME_STAMP)
VALUES (USER, :NEW.V_NAMES, :NEW.V_AGES, SYSTIMESTAMP);
END;
/
-> UPDATE
UPDATE VEHICLES
SET V_NAMES = 'BIKE'
WHERE V_NAMES ='AIRPLAIN TOY';
:OLD
-> UPDATE
SET SERVEROUTPUT ON;
CREATE OR REPLACE TRIGGER TRG_VEHICLES_AUDIT_OLD
AFTER UPDATE ON VEHICLES
FOR EACH ROW
BEGIN
INSERT INTO VEHICLES_AUDIT_LOG (USER_NAME, NEW_V_NAME, NEW_V_AGE,
TIME_STAMP)
VALUES (USER, :OLD.V_NAMES, :OLD.V_AGES, SYSTIMESTAMP);
END;
/
UPDATE VEHICLES
SET V_NAMES = 'HUSSAIN CYCLE'
WHERE V_NAMES ='CYCLE';
-> DELETE
SET SERVEROUTPUT ON;
CREATE OR REPLACE TRIGGER DEL_VEHICLES_AUDIT_OLD
AFTER DELETE ON VEHICLES
FOR EACH ROW
BEGIN
INSERT INTO VEHICLES_AUDIT_LOG (USER_NAME, NEW_V_NAME, NEW_V_AGE,
TIME_STAMP)
VALUES (USER, :OLD.V_NAMES, :OLD.V_AGES, SYSTIMESTAMP);
END;
/
Example
For the demonstration we will use the table ‘Superheroes’ which we created in the previous tutorial.
Suppose you want to keep an eye on the users who are inserting, updating or deleting data from the ‘Superheroes’
table. Let’s see how we can achieve this. To do so we will need another table in which we can journal the auditing
data entries.
This table sh_audit has 5 columns which will store the auditing information such as the new data inserted or
updated, old data which is updated or deleted from the table, name of the user who did it along with the date and
time, also the type of DML operation performed.
Next we will write a trigger on the source table superheroes and will store the data into the auditing table sh_audit.
On successful compilation this trigger will insert a row containing auditing data such as the data inserted, updated
and deleted from the source table superheroes along with the username who tampered the data as well as the date
and time when it was done and also the name of DML statement executed by user to tamper the data of your table.
These Psuedo Records helps us in fetching data from the sh_name column of the underlying source table
‘Superheroes’ and storing it into the audit table sh_audit.
Pseudo Record ‘: NEW’, allows you to access a row currently being processed. In other words, when a row is being
inserted or updated into the superheroes table. Whereas Pseudo Record ‘: OLD’ allows you to access a row which is
already being either Updated or Deleted from the superheroes table.
In order to fetch the data from the source table, you have to first write the proper Pseudo Record (New/Old)
followed by dot (.) and the name of the column of the source table whose value you want to fetch. For example in
our case we want to fetch the data from sh_name column which belongs to our source table superheroes. Thus we
will write “: New. sh_name” for fetching the current value and to fetch the previously stored value we will write “:
OLD. sh_name”. Once the values are fetched the INSERT dml will store these values into the respective columns of
the audit table.
Once you execute and compile this trigger then you can take it on a test run by writing DML statements on the
underlying source table ‘Superheroes’. For example you can try Inserting a row in superheroes table and then check
the audit table whether there is some data or not.
INSERT INTO SUPERHEROES VALUES('SPYDER MAN');
As soon as you execute any of these DML statements on the underlying table superheroes, the trigger will execute in
the background and insert the audit data into the audit table sh_audit.
For the demonstration we will require two identical tables; one which will serve as your main table that will accept
the data from your database user and the second which will be your backup table
To create a table for backup, you can use the CREATE TABLE statement in SQL. The new table will have
the same structure as the original table from which you want to create a backup. Here's the SQL query to
create a backup table.
SYNTAX
In this Syntax:
“CREATE TABLE BACK_UP_TABLE_NAME “ specifies the name of the new table you want to create and
“AS SELECT * FROM ORIGINAL_TABLE_NAME WHERE 1=0” is a subquery that selects no rows
(WHERE 1=0 which is evaluated as false) from the original table. By doing this, you create an empty table
with the same structure but without any data.
If we provide the WHERE clause as (WHERE 1=1) when creating the backup table, it will copy all the data
from the original table to the backup table. The condition 1=1 always evaluates to true, so the SELECT query
will fetch all the rows from the original table.
Syntax:
Syntax is pretty simple CREATE TABLE is oracle reserved phrase followed by the user defined name of the
table ‘table_name_1’ with which you want to create your new table then we have mandatory keyword ‘AS’
followed by a simple SELECT DML statement.
Table_name_2 is the name of the table whose copy you want to make and table_name_1 is the name of your
new table.
Examples:
For the demonstration we will use the Employees table of HR sample schema of the Oracle Database.
Copying the exact structure and data of the employees table can be done by writing a very simple Create table
statement. That statement will be
Successful execution of the above command will create the employees_copy which will be having the same
structure and data as of the Employees table of HR schema.
E.g. 2. How to copy specific columns of a table along with their data.
Now suppose you want to copy only first_name, last_name or email columns with data of employees table in
this case CREATE TABLE statement will be.
Successful execution of the above command will create the table employees_copy this time with only column
first_name, last_name and email and the data.
E.g. 3. How to copy only structure of the table without the data.
Sometimes you might be required to copy only the structure of the table sans the data. In this case what you
can do is copy the whole table as shown in above examples and then truncate it later but this will need two
operations or two different commands to execute for a single task: Such a waste of time & resources when
you can accomplish the same just by writing a simple “Create Table As command”.
The Create Table command will remain the same as shown in above examples. You just need to add a where
clause which will never set to be true or always false for example where clause such as ‘Cats’ = ‘Dog’ or 0=1.
Let’s see how
Next we will have to create an identical table to this one which will work as our backup table.
Next we have to write the trigger which will insert, update or delete the rows from the backup table when someone
does the same with our main table.
IF INSERTING THEN
UPDATE EMPLOYEES_BACKUP
SET
EMP_ID = :NEW.EMP_ID,
EMP_NAME = :NEW.EMP_NAME,
EMP_ROLE = :NEW.EMP_ROLE,
EMP_SALARY = :NEW.EMP_SALARY
WHERE
EMP_ID = :OLD.EMP_ID;
END IF;
END;
/
After successful execution of the trigger, changes from the main table will get reflected on the backup table
too.
Verification
INSERT INTO EMPLOYEES VALUES(1,'MAHAMMAD HUSSAIN','SYSTEM ENGINEER',374000);
INSERT INTO EMPLOYEES VALUES(2,'VAMSI','SYSTEM ENGINEER',376000);
INSERT INTO EMPLOYEES VALUES(3,'GIRISH','DEVELOPER',402000);
In Oracle SQL, there is a one-to-one relationship between a user account and a schema. This means that each
user account is associated with a single schema, and the name of the user account is the same as the name of
the schema it owns. When a user is created, a schema with the same name is automatically created for that
user.
The relationship between a user account and a schema can be summarized as follows:
User Account:
A user account is an entity used to connect to the Oracle database. It is identified by a unique username and
is associated with a password. When a user account connects to the database, it gains access to its associated
schema and the objects (tables, views, procedures, etc.) within that schema.
Schema:
A schema in Oracle is a logical container for database objects. It is associated with a specific user account,
and its name is the same as the username of that user. Any objects created by the user account are
automatically created within its associated schema. The schema provides a namespace for organizing and
managing database objects owned by that user.
For example, if you have a user account with the username "john," there will also be a schema named
"john" associated with that user. Any tables, views, or other objects created by the user account "john" will
be stored in the "john" schema.
This one-to-one relationship between user accounts and schemas simplifies the management of database
objects and access control, making it easier to control who can access and modify specific objects within the
database. However, it is essential to grant the appropriate privileges to users to ensure proper data security
and access control.
DDL triggers are the triggers which are created over DDL statements such as CREATE, DROP or ALTER. Using
this type of trigger you can monitor the behavior and force rules on your DDL statements.
In order to proceed ahead and start writing the trigger first we need a table in which we can journal the auditing
information created by the trigger.
In case of schema/user auditing using DDL trigger creates this table in the same schema which you are auditing and
in case of Database auditing using DDL trigger create this table in sys or system schema (sys or system both
schemas can be used to perform database auditing).
sysdate: This is a built-in Oracle function that returns the current date and time.
The sys_context function is used to access various session-specific and system-related information within
Oracle databases. It takes two arguments:
The first argument represents the namespace of the context item you want to retrieve. In this case, 'USERENV'
is the namespace used to access user environment-related information.
The second argument specifies the parameter name or context item within the namespace. For the current user's
name, we use 'CURRENT_USER' as the parameter name.
ora_dict_obj_type: This is a placeholder for a value that represents the type of the object involved in the
operation that triggered the trigger (assuming this is part of a trigger definition). The value will depend on the
type of the object (e.g., TABLE, VIEW, TRIGGER, etc.).
ora_dict_obj_name: Similar to the previous one, this is a placeholder for a value that represents the name of
the object involved in the operation.
ora_sysevent: This is another placeholder for a value that represents the type of event (e.g., INSERT,
UPDATE, DELETE) that triggered the trigger (again, assuming this is part of a trigger definition).
If you will notice carefully the second line of the code (“AFTER DDL ON SCHEMA”) indicates that this trigger
will work on the schema in which it is created. On successful compilation this trigger will insert the respective
information such as the date when the DDL is executed, username who executed the DDL, type of database object
created, name of the object given by the user at the time of its creation and the type of DDL into the table which we
created earlier.
database is a physical container that holds data, while a schema is a logical container within that database that
defines the structure and organization of the data. The database contains multiple schemas, and each schema
contains various database objects related to a specific part of the application or system.
the main difference is that a DDL trigger for schema auditing is limited to capturing changes within a
specific schema, while a DDL trigger for database auditing captures changes across the entire database.
**Database in SQL:**
A database in SQL (Structured Query Language) is a collection of organized data that is stored, managed,
and accessed electronically. It is designed to efficiently store and retrieve data to support various applications
and processes. Databases consist of tables, which are structured collections of data with rows and columns.
**Schema in SQL:**
A schema in SQL is a logical container or namespace within a database. It defines the structure of the
database by describing how the data is organized and the relationships between different elements, such as
tables, views, procedures, and functions. A schema acts as a blueprint for organizing and accessing the data
within a database.
1. **Scope:**
- A database is the top-level container that holds all the data and information for a specific application or
domain.
- A schema, on the other hand, is a subset of a database and represents a specific part or logical grouping of
the database objects.
2. **Organization:**
- In a database, multiple schemas can exist to organize data and objects efficiently. Each schema can have
its own tables, views, and other database objects.
- A schema defines the structure and layout of these objects, specifying their names, datatypes, and
relationships.
**Example:**
Let's consider a scenario of an e-commerce website:
**Database:** The e-commerce website's database contains all the data related to customers, products,
orders, etc. It is the entire collection of data.
**Schema:** Within the database, we can have multiple schemas to segregate the data for different aspects
of the website. For example, we can have separate schemas for 'Customers', 'Products', and 'Orders'. Each
schema will contain tables specific to its purpose.
**Customers Schema:**
```
Tables:
1. customer_info
- customer_id (Primary Key)
- name
- email
- address
2. customer_orders
- order_id (Primary Key)
- customer_id (Foreign Key)
- order_date
- total_amount
```
**Products Schema:**
```
Tables:
1. product_info
- product_id (Primary Key)
- name
- price
- description
2. product_stock
- product_id (Foreign Key)
- available_quantity
```
**Orders Schema:**
```
Tables:
1. order_items
- order_item_id (Primary Key)
- order_id (Foreign Key)
- product_id (Foreign Key)
- quantity
- subtotal
```
In this example, we have one database (the e-commerce website's database) with three schemas ('Customers',
'Products', and 'Orders'), each containing tables specific to their respective data types. The schema helps
organize the data and maintain the relationships between different entities more effectively.
Database event triggers also known as system event triggers come into action when some system event occurs such
as database log on, log off, start up or shut down. These types of triggers are majorly used for monitoring activity of
the system events and have been proved quite a powerful tool for a DBA.
Syntax
Suppose user HR is a control freak and wants to monitor its every log on and log off activity. In this case what HR
can do is, create event triggers on Log on and log off database event in its own schema.
Connect to the database using the user/schema in which you want to create the trigger. For the demonstration I will
connect using my HR user.
Connect hr;
Next you will need a table to store the logon and logoff data.
Now you are connected to the database using the desired user and also have the table ready to store the data. The
only thing which is left is the trigger.
This trigger will fire every time HR user logs on to the database and respective values will be stored into the table
which we just created in the step 2.
Example
Logon to the database using any user such as HR or any other you want.
Create a table to dump the data generated by your schema level logoff trigger.
Below written trigger will execute every time user HR logs off from the database.
On successful compilation this trigger will fire every time the user, using which it was created, logs off from the
database and that user in our case is HR.
As I said above that this trigger is bound to work only for the user in which it is created. What if we want to keep
track of all the logoff activities of all the users of the database? In such a scenario we can write a database level
system event trigger.
As the name suggests Database event trigger fires for the entire database or you can say that it fires for all the
schemas created under the database in which these triggers are created which is unlike Schema Level System Event
trigger which runs for a specific schema only.
Also database level system event trigger can only be created by high privileged users such as sys or system or any
user who has ADMINISTER DATABASE TRIGGER system privilege where Schema level system event trigger
can be created by any user of the database on its own schema which has Create Trigger System Privilege.
Example: How To Create Database Level Logoff event Trigger In Oracle PL/SQL
Database Level Logoff Event Trigger is pretty similar to the trigger which we just saw for schema
As only the user with ADMINISTER DATABASE TRIGGER system privilege can create a database level event
trigger thus we need to make sure that this time we should log on to the database using one of these users.
Again in order to store the audit data we need to create a table where this trigger will journal the entries of all the
users. The structure of the table will be pretty similar to the above one except one extra column for storing the
username with the help of which we can clearly identify the details and avoid the confusion.
Following Trigger will keep an eye on the logoff activity of the user of the database.
CREATE OR REPLACE TRIGGER db_lgof_audit
BEFORE LOGOFF ON DATABASE
BEGIN
INSERT INTO db_evnt_audit
VALUES(
user,
ora_sysevent,
NULL,
NULL,
SYSDATE,
TO_CHAR(sysdate, 'hh24:mi:ss')
);
END;
/
Code is very similar to the previous one except that this time this trigger will execute for all the users of the
database. This we are making sure by using the keyword DATABASE instead of SCHEMA in the second line of the
trigger unlike the previous trigger.
There can be various ways of taking advantage of these triggers; it depends on your creativity.
Startup Trigger
Startup triggers execute during the startup process of the database. In order to create a database event trigger for
shutdown and startup events we either need to logon to the database as a user with DBA privileges such as sys or we
must possess the ADMINISTER DATABASE TRIGGER system privilege.
Example
In order to create a trigger on Startup Database Event first we will have to logon to our database using the user SYS
with DBA privileges.
To store the data generated by the execution of trigger we will require a table.
On successful execution this trigger will insert a row of data each time database starts up.
Shutdown Triggers
SHUTDOWN triggers execute before database shutdown processing is performed. Similar to the startup trigger,
only a user with DBA role or ADMINISTER DATABASE TRIGGER system privilege can create a shutdown
trigger.
Example.
First 2 steps of creating a database event shutdown triggers are same as that of the startup trigger which we saw
above.
Table used in this trigger is the same one which we created during the coding of the Startup trigger above.
SHUTDOWN triggers execute only when the database is shut down using NORMAL or IMMEDIATE mode. They
do not execute when the database is shut down using ABORT mode or when the database crashes.
You can also use shutdown database event triggers for gathering your database system statistics. Here is an example
Set operators
Aggregate functions
GROUP BY, CONNECT BY, or START WITH clauses
The DISTINCT operator
Joins (however, some join views are updatable)
In case a view consists of pseudo columns or expressions, then it is only possible to update it with an UPDATE
statement and that also when it does not refer to any such pseudo columns or for that matter, expressions.
Syntax
If you noticed carefully then you’ll see that we do not have either BEFORE or AFTER clause in the syntax. This is
because unlike other triggers, instead-of trigger executes neither BEFORE nor AFTER but instead of a triggering
event. That is why we do not need to specify either BEFORE or AFTER clause.
Examples
Instead-of Insert Trigger
Instead-of trigger can be best demonstrated using a View joining two or more tables. Thus in this example I will
create two simple tables and will then create a view over them. After that I will create an Instead of trigger for Insert
operation on this view.
Table 2- Subject
This is a non-updatable view which you can confirm by executing any DML statement over it. Error as a result of
DML operation on this view will be your confirmation.
Next I will create an Instead-of Insert trigger over the view vw_rebellionrider that we created in step 2.
On successful execution, this trigger will insert a new row of data into both the underlying tables of the view
vw_rebellionrider. You can confirm that by executing an insert DML over the view.
Example:-
Tables (Trainer and Subject) and View (VW_RebellionRider) used in this example are the same as the ones we
created in the previous tutorial.
On successful execution this trigger will let you execute an Update DML on the view.
Needless to say that executing DELETE DML on this view will return an error because of its non-updatable nature.
Thus the only way to perform DELETE DML on this view is by using an Instead of trigger. Let’s quickly create
one.
When you execute a SELECT statement, a cursor is created in the background to handle the result set. You can then
use this cursor to fetch each row of data and perform actions on it individually.
Cursors are particularly useful when you need to process data row by row or when you want more control over how
you handle the query results. They help you work with the data in a procedural manner, letting you perform
calculations, apply conditions, and do other operations on each row separately.
In summary, a cursor in Oracle SQL is a tool that allows you to fetch and process data row by row from a query
result, giving you the ability to work with the data in a more controlled and step-by-step manner.
Cursor is a pointer to a memory area called context area. This context area is a memory region inside the
Process Global Area or PGA assigned to hold the information about the processing of a SELECT statement
or DML Statement such as INSERT, DELETE, UPDATE or MERGE.
Let’s dig a little deeper and see what the context area is?
The context area is a special memory region inside the Process Global Area or PGA which helps oracle
server in processing an SQL statement by holding the important information about that statement.
Using cursor you can control the context area as it is a pointer to the same.
Advantages of Cursors
1.Cursor is names thus you can reference it in your program whenever you want.
2.Cursor allows you to fetch and process rows returned by a SELECT statement by a row at a time.
Implicit cursor
Explicit cursor
Implicit Cursors in Oracle Database
As the name suggests these are the cursors which are automatically created by the oracle server every time an SQL
DML statement is executed. User cannot control the behavior of these cursors. Oracle server creates an implicit
cursor in the background for any PL/SQL block which executes an SQL statement as long as an explicit cursor does
not exist for that SQL statement.
Oracle server associates a cursor with every DML statement. Each of the Update & Delete statements has cursors
which are responsible to identify those set of rows that are affected by the operation. Also the implicit cursor fulfills
the need of a place for an Insert statement to receive the data that is to be inserted into the database.
1.Since Explicit cursors are user defined hence they give you more programmatic control on your program.
2.Explicit cursors are more efficient as compared to implicit cursors as in latters case it is hard to track data errors.
Declare
Open
Fetch
Close
In case of implicit cursors oracle server performs all these steps automatically for you.
1) Declare the cursor: It defines the cursor with a name and the associated SELECT statement.
2) Open the cursor: It is used to allocate memory for the cursor and make it easy to fetch the rows
returned by the SQL statements into it.
3) Fetch the cursor: It is used to access one row at a time. You can fetch rows from the above-opened
cursor as follows:
4) Close the cursor:lt is used to release the allocated memory. The following syntax is used to close the
above-opened cursors.
Cursor Attributes
-------------------------------
%FQUND
%NOTFOUND
its return value is TRUE if DML statements like INSERT, DELETE and UPDATE affect no row, or a
SELECT INTO statement retum
no rows. Otherwise it returns FALSE. It is a just opposite of %FOUND
%ISOPEN
always retums FALSE for implicit cursors, because the SQL cursor is automatically closed after
executing its associated SOL
statements.
%ROWCOUNT
It returns the number of rows affected by DML statements like INSERT, DELETE, and UPDATE or
returned by a SELECT INTO
Syntax
CURSOR cursor_name IS select_statement;
1.All the variables including bind variables in the WHERE clause of a SELECT statement are examined.
2.Based on the values of the variables, the active set is determined, and the PL/SQL engine executes the query for
that cursor. Variables are examined at cursor open time.
Syntax
OPEN cursor_name;
Syntax
FETCH cursor_name INTO PL/SQL variable;
Or
FETCH cursor_name INTO PL/SQL record;
1.The use of a FETCH command is to retrieve one row at a time from the active set. This is usually done inside a
loop. The values of each row in the active set can then be stored in the corresponding variables or PL/SQL record
one at a time, performing operations on each one successively.
2.After completion of each FETCH, the active set pointer is moved forward to the next row. Therefore, each FETCH
returns successive rows of the active set, until the entire set is returned. The last FETCH does not assign values to
the output variables as they still contain their previous values.
Syntax
CLOSE cursor_name;
Basic Programming Structure of the Cursor
Here is the basic programming structure of the cursor in oracle database.
DECLARE
CURSOR cursor_name IS select_statement;
BEGIN
OPEN cursor_name;
FETCH cursor_name INTO PL/SQL variable [PL/SQL record];
CLOSE cursor_name;
END;
/
Cursor Attributes
Oracle provides four attributes which work in correlation with cursors. These attributes are:
%FOUND
%NOTFOUND
%ISOPEN
%ROWCOUNT
First three attributes ‘Found’, ‘NotFound’ and ‘IsOpen’ are Boolean attributes whereas the last one
‘RowCount’ is a numeric attribute.
%Found
Cursor attribute ‘Found’ is a Boolean attribute which returns TRUE if the previous FETCH command returned
a row otherwise it returns FALSE.
%NotFound
‘Not Found’ cursor attribute is also a Boolean attribute which returns TRUE only when previous FETCH
command of the cursor did not return a row otherwise this attribute will return FALSE.
%IsOpen
Again ‘Is Open’ Cursor attribute is a Boolean attribute which you can use to check whether your cursor is open
or not. It returns TRUE if the cursor is open otherwise it returns FALSE.
%RowCount
Row count cursor attribute is a numeric attribute which means it returns a numeric value as a result and that
value will be the number of records fetched from a cursor at that point in time.
26.How To Create An Explicit Cursor In Oracle Database
As we have already learnt that whenever we execute a DML statement, the oracle server creates an implicit cursor in
the background. As these cursors are created by oracle server itself thus user does not have much programmatic
control on them. In case if you want to control your own DMLs then you need to write an explicit cursor.
So let’s quickly see how you can create your own database cursor in oracle database.
Steven
Neena
Lex
Alexander
Bruce
Bruce
We used EMPLOYEE table of HR sample Schema for creating the above explicit cursor.Declaration of your cursor
can only be done in the “Declaration” section of the PL/SQL block and the rest of the steps of explicit cursor
creation cycle must be done in the execution section of a PL/SQL block.
Definition:
Cursor parameter can be appropriately defined as an explicit cursor that accepts arguments from the user in
the form of parameter.
Syntax of declaring a cursor parameter is pretty similar to that of the simple cursor except the addition of
parameters enclosed in the parenthesis.
OPEN cur _ name (argument list)
You have to provide corresponding arguments for each parameter that are specified during the declaration. Rest
of the steps are the same as that of the simple cursor.
There are few things which you have to take care of while specifying the parameters in your explicit
cursor.
1.In case of multiple parameters, always separate parameters and the corresponding arguments in the list from
each other using comma (,).
2.You can specify as many parameters as you need just make sure to include an argument in parameter list for
each parameter when you open the cursor.
3.While specifying a parameter during the declaration of the explicit cursor only specify the data type not the
data width.
The simplest answer is whenever you need to use your cursor in more than one place with different values for
the same WHERE clause of your SELECT statement.
Steven
Neena
Lex
Alexander
Bruce
David
Valli
Diana
Nancy
Daniel
Daniel
To overcome this restriction, we have the option called default value. Default value is the value which you
assign to the parameter of your cursor during the declaration of the cursor.
Randall 191
Sarah 192
Britney 193
Samuel 194
Vance 195
Alana 196
Kevin 197
Donald 198
Douglas 199
Jennifer 200
Michael 201
Pat 202
Susan 203
Hermann 204
Shelley 205
William 206
As you can see in the above code I assigned a value (which is 190) using assignment operator to the parameter
CUR_VAR_EMP_ID in the cursor declaration and nothing while opening the cursor. Upon the execution this
PL/SQL block will show you the first name and employee id of all the employees who have employee id
greater than 190.
If you compare the result of both the codes demonstrated in the above examples you will see the difference
because the result returned by Example 1 is according to the default value (which is 190) which you specified
during the declaration while the result returned by Example 2 will be according to the argument (which is 200)
you have specified in the OPEN cursor statement.
Definition:
Cursor for Loop Is an Extension of the Numeric For Loop provided by Oracle PL/SQL which works on
specified cursors and performs OPEN, FETCH & CLOSE cursor statements implicitly in
where loop index is a row type record variable which will hold the data return by the cursor
Michael Hartstein
Pat Fay
Susan Mavris
Hermann Baer
Shelley Higgins
William Gietz
As you can see in the above code, instead of declaring a cursor into a separate declaration section of PL/SQL
block we can write the Cursor’s SELECT DML statement right inside the loop statement after IN keyword.
Just remember:
1. Directly write the SELECT statement without specifying the cursor name into the loop statement.
2. Enclose the SELECT statement into parenthesis.
3. Do not terminate the SELECT statement with a semicolon (;)
This loop will execute for each row returned by the specified cursor and it will terminate either when there is
no row to return or there is an occurrence of an exception.
OR
SET SERVEROUTPUT ON;
DECLARE
CURSOR CUR_FULL_NAME(VAR_EMP_ID NUMBER :=200)IS
SELECT FIRST_NAME,LAST_NAME FROM HR.EMPLOYEES WHERE
EMPLOYEE_ID>VAR_EMP_ID;
BEGIN
FOR LOOP_INDEX IN CUR_FULL_NAME
LOOP
DBMS_OUTPUT.PUT_LINE(LOOP_INDEX.first_name||' '||LOOP_INDEX.last_name);
END LOOP;
END;
/
Michael Hartstein
Pat Fay
Susan Mavris
Hermann Baer
Shelley Higgins
William Gietz
You can pass the values for the parameters of your cursor just by simply writing the argument right after the
name of your cursor in loop statement as shown in the above example (Statement In bold). Always remember
to enclose the arguments inside the parenthesis.
Definition:-
A record is a group of related data items stored in fields, each with its own name and datatype.
Variable Name: A user defined name given to the variable. You have to specify the name of the variable
which could be anything. But you have to follow the oracle guidelines for variable name.
Table Name: Table name will be the name of the table over which the record datatype is created. This table
will serve as the base table for the record. Also the Oracle Server will then create corresponding fields in the
record that will have the same name as that of a column in the table.
%ROWTYPE: Attribute which indicates the compiler that the variable which is declared is of Record Type.
The syntax of cursor based record is pretty similar to the one which we just saw. You just have to specify the
name of the cursor in place of table name, rest of the things remain same.
Record_variable_name.column_name_of_the_table;
Using dot (.) notation you can access the data stored into the field of the record.
32. What Are Table Based Record Datatypes In Oracle
Database
In the previous section we saw that the record datatype variables are composite data structures made up of
different components called fields that have the same name and data types as that of the columns of a table
using which you created that record. There we saw that there are three types of record variables available in
Oracle Database. In this section we will concentrate on the first type of record variable which is “ Table Based
Record Datatypes” Variables
Whenever you declare a record type variable oracle engine will declare a composite data structure with fields
corresponding to each column of the specified table. For example if we have a record variable created using
Employees table then that variable has 11 fields corresponding to 11 columns of the employees table. Also all
these fields have the same name, data type and data width as that of the columns of the table.
For example
That is the declaration section of an anonymous PL/SQL block where we declared a record type variable with
the name v_emp. V_emp record variable is based on employees table of the HR sample user. As this record
variable is based on “employee” table of HR sample user thus it will have 11 fields corresponding to the 11
columns of the employees table.
1. By fetching data from all the columns of a row of a table into the record variable using SELECT-INTO
statement.
2. By fetching data from selected columns of the table into the record variable using SELECT-INTO statement.
3. By directly assigning the value into the record variable using assignment operator.
We will discuss each of the above ways of initializing a record data type variable one tutorial at a time. In this
tutorial we will focus on the first way of initializing database records which is by Fetching data from all the
columns of a row of a table.
As we are talking about fetching data from all the columns thus we are using the SELECT * statement and
storing the data into our record variable V_EMP.
NOTE
Take a note here that a table based record variable can hold data of a single row at a time, thus you have to
make sure that the SELECT-INTO statement returns the data from one row only and for that you can filter the
data using WHERE clause, as we did in the above statement.
The answer is No, we cannot use the same process shown in the previous tutorial for initializing a record datatype
variable by fetching data from select columns of a table. The execution of the following example where we are using
the data from one column “First Name” of the “Employees” table for initializing the record datatype variable
“v_emp” will return an error.
Error report -
ORA-06550: line 4, column 40:
PL/SQL: ORA-00913: too many values
ORA-06550: line 4, column 1:
PL/SQL: SQL Statement ignored
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
That error is “PL/SQL: ORA-00913: too many values” So what does this error means? Why is it saying “too many
values” even when we are fetching only one data. I know sometimes PL/SQL error can be deceptive and confusing.
In order to find out the solution of this problem and understand this error we have to recall what we learnt in the
previous tutorial. There we learnt that Database Records are composite data structures made up of multiple fields
which share same name, datatype and data width as that of the columns of the table over which it is created. And the
data which was fetched gets stored into these fields.
In case of initializing a record variable by fetching data from all the columns of a table, we don’t have to do
anything, oracle engine does all the dirty work in the background for you. It first fetches the data from the table and
then stores that data into the corresponding field into the record which has the same data type and data width, and
for that matter also shares the same name.
But when it comes to initializing a record datatype variable by fetching the data from selected columns we have to
do all this work manually. We have to specify the name of the column from which we want to fetch the data and
then we have to specify the name of the field where we want to store that data.
In the above example we did specify the column name of the table whose data we want to fetch but we didn’t
specify the name of the record’s field where we want to store the fetched data. That confuses the compiler on where
to store the data which ultimately causes the error.
Now the question here is that how to specify the record data type field’s name? We can specify the name of the field
of the record variable using Dot (.) notation where we first write the name of the already declared record variable
followed by a dot (.) and the name of the field. And luckily both the columns of the table and fields of the record
share the same name.
So now that we have learnt why we are having PL/SQL ORA-00913 error on initializing the record data type
variable using data from select columns. Let’s modify the above example accordingly and try to resolve it.
Example : Initialize the Record Datatype variable using data from
Multiple Columns.
SET SERVEROUTPUT ON;
DECLARE
V_VAR HR.EMPLOYEES%ROWTYPE;
BEGIN
SELECT first_name,last_name INTO V_VAR.first_name,V_VAR.last_name FROM
HR.EMPLOYEES WHERE EMPLOYEE_ID =105;
DBMS_OUTPUT.PUT_LINE('FULL NAME OF THE EMPLOYEE = '||V_VAR.FIRST_NAME||' '||
V_VAR.LAST_NAME);
END;
/
Once you have created your cursor then you are all set to declare your Cursor based Record variable.
VAR_EMP CUR_HUSSAIN %ROWTYPE;
Declaration of Cursor Based Record is pretty much similar to the declaration of table based record. The declaration
starts with the name of the record variable, which is completely user defined followed by the name of an already
created cursor. And at the end “%ROWTYPE” attribute which indicates that we are declaring a Record Datatype
variable to the compiler.
BEGIN
OPEN CUR_HUSSAIN;
FETCH CUR_HUSSAIN INTO VAR_EMP;
Every cursor needs to be opened before being used. Thus here we first opened the cursor and then using FETCH-
INTO statement we fetched the data into the record variable “var_emp”.
DBMS_OUTPUT.PUT_LINE (VAR_EMP.FIRST_NAME);
DBMS_OUTPUT.PUT_LINE (VAR_EMP.SALARY);
You can see in the above two statements that once again we used the Dot (.) notation for fetching the data from the
record variable. Though these two statements look very similar to one which we have seen in table based record
variable tutorial, but they are not. In case of table based record we have to write the name of the column of the table
but in case of cursor based record we can only write the name of those columns of the table which we specified in
the SELECT-List of the cursor.
Once you have declared, initialize and access the data then make sure to close the cursor.
Now let’s compile all the above line of codes (LOCs) together and make them into a single PL/SQL block.
David
Austin
In PL/SQL, you cannot declare a cursor-based record variable before declaring the cursor itself. The
cursor definition must appear before you declare a record variable based on it.
35.Cursor Based Record Datatype With Cursor Returning
Multiple Values In Oracle Database
We have already seen in the previous section how to create Cursor based Record Type Variable based on Simple
Cursor which returns a single row of data. Now the question arises here is that can we use the same single record
datatype variable with the cursor which returns multiple rows of data?. Lets see to handle multiple values returned
by a cursor using single cursor based record datatype variable
Unlike the cursor from the previous tutorial which is returning a single row of data, this cursor will return multiple
rows. All these rows will consist of the first name and salary of all the employees with employee id greater than 200.
var_emp cur_hussain%rowtype;
Var_emp is the record type variable and as it is based on the cursor cur_hussain thus we can proudly call it a Cursor-
Based record type variable. Now we have to see whether this single record variable is capable of holding all the data
returned by the underlying cursor cur_hussain
begin
open cur_hussain ;
loop
fetch cur_hussain into var_emp;
exit when cur_hussain%notfound;
dbms_output.put_line(var_emp.first_name||' '||var_emp.salary);
end loop;
close cur_hussain;
end;
/
So that is it. That’s all we have to. Now let’s combine all these chunks of code which we saw in different steps
above into a single anonymous PL/SQL block.
Michael 13000
Pat 6000
Susan 6500
Hermann 10000
Shelley 12008
William 8300
When you compile and run the above code you will get all the data which FETCH-INTO statement fetched from the
cursor cur_hussain and stored into the Cursor-based Record variable var_emp. This implies that we can indeed
handle multiple rows of data using a single Cursor Based Record.
Here is the code done using Cursor For-Loop which is equivalent to the above code. As you can see it
is much less complex with few Line-of-Codes (LOCs).
Michael 13000
Pat 6000
Susan 6500
Hermann 10000
Shelley 12008
William 8300
The creation process of user define record variable is divided into two parts. Before defining the record we first need
to define the TYPE for the record variable. This TYPE will become the base of the User Define Record variable and
will help in driving its structure. Once the TYPE is successfully declared then we can use it for creating our user
define record variable.
Below is the syntax for creating the TYPE for User Defined Record Datatype Variable.
Once we have our TYPE declared we are all set to create our Record Variable. This variable will then acquire all the
properties of the type using which it is created. And here is the syntax for creating the user define record datatype
variable.
record_name TYPE_NAME;
Did you notice that unlike the Table based or Cursor Based Record Variable we do not have to use %ROWTYPE
attribute here for declaring the record variable because we are deriving it from user defined record
var_ur emp_dept;
This above PL/SQL statement will create a record variable with the name var_ur.
Next we will write the execution section. In the execution section we will have a SELECT statement which will be
joining employees table and departments table and returning the first name and department name of the specific
employee.
BEGIN
SELECT first_name , department_name
INTO var_ur.f_name, var_ur.d_name
FROM hr.employees join hr.departments
Using (department_id) WHERE employee_id = 100;
The select statement which we have here will return the first name and the department name of the employee whose
employee id is 100. The data for both the columns are coming from different tables thus we used a JOIN here. As
there are two different tables involved in the query thus in such a situation use of Table Based Record Variable is
not possible therefore the viable solution is the user define record variable.
Let’s join all the above chunks of codes together into a single anonymous PL/SQL block.
That is how we create a User Defined Record Datatype Variable in Oracle Database.
PL/SQL functions are code blocks within Oracle Database used to compute and return a single value. They
accept parameters, process data, and encapsulate logic for reuse. Functions are invoked from SQL, other
PL/SQL code, or applications, enhancing modularity and performance. While limited to returning a value, they
contribute to efficient and organized database-driven applications.
There are two types of PL/SQL functions in Oracle Database, these are
1.Pass-by-Value Functions
Behavior: In pass-by-value functions, the values of the actual parameters (arguments) are copied into the
function's parameters. This means that any changes made to the parameters within the function do not affect the
original values outside the function.
Purpose: These functions are commonly used for calculations and operations where you don't want the original
values to change.
Example:
2.Pass-by-Reference functions
Behavior: In pass-by-reference functions, the function receives a reference (memory address) to the original
variables as parameters. Any changes made to the parameters within the function are reflected in the original
variables.
Purpose: These functions are used when you want to modify the original values or when you need to return
multiple values from the function.
Example:
In both types of functions, the goal is to encapsulate logic for reusability, but they handle parameter values
differently. By default, PL/SQL uses pass-by-value, which means that modifications within the function do not
affect the original values. However, if you want modifications to affect the original values, you need to use pass-by-
reference, often indicated using the IN OUT or OUT keywords.
When choosing between these types, consider the nature of the data you're working with and the desired behavior of
the function. Pass-by-value functions are useful when you want to maintain the immutability of the original values,
while pass-by-reference functions are suitable for cases where you need to modify those values directly.
In Oracle Database both types of functions should have to return some values and these values should be a
valid SQL or PL/SQL datatype.
Syntax of PL/SQL Functions in Oracle Database
Depending on your creativity and programming skills, a PL/SQL function can be called by multiple ways. Here are
some general ways of calling a PL/SQL function in Oracle Database
>You can use SQL*Plus utility of the Oracle Database to invoke a PL/SQL function that can be called from PL/SQL
as procedural statement.
>You can even call a function directly into a SELECT or DML statement.
The header consists of the signature of the function or the declaration of the PL/SQL function.
--Function Header
BEGIN
--Area of Circle pi*r*r;
area := pi * (radius * radius);
RETURN area;
END;
/
Quick Info:
To calculate the square of the circle’s radius in the area of circle, you can also use the inbuilt function of POWER (p,
q). This function takes two numeric input and returns one numeric value which will be the answer to the arithmetic
expression of p raise to q.
AREA NUMBER(7,3);
PI NUMBER(7,3) :=3.141;
BEGIN
AREA := PI*(RADIUS*RADIUS);
RETURN AREA;
END;
/
-- CALCULATING AREA OF A CIRCLE USING ABOVE CREATED FUNCTION
CIRCLE_AREA
615.636
TABLE CREATION
The above Syntax of PL/SQL stored procedure is pretty much similar to the syntax of PL/SQL Functions that we
saw in the last PL/SQL tutorial. Except for two things:
A core difference between a PL/SQL Function and a stored procedure is that unlike Functions a stored procedure
does not return any value.
2. AUTHID Clause.
The AUTHID clause is used for setting the authority model for the PL/SQL Procedures. This clause has two flags.
>>DEFINER
>>CURRENT_USER
As this clause is optional thus in case if you do not use AUTHID clause then Oracle Engine will set the authority
(AUTHID) to the DEFINER by default for you. Now, you must be wondering what these DEFINER and
CURRENT_USER rights are?
DEFINER right: Definer right is the default right assigned to the procedure by oracle engine. This right means
anyone with Execution Privilege on the procedure acts as if they are the owner of the schema in which the privilege
is created.
CURRENT_USER right: Setting the authority level of a stored procedure to the current_user right overrides the
default right which is definer and change it to the invoker rights.
Invoker right authority means that you call the procedure to act on your local data and it requires that you replicate
data objects in any participating schema.
Some Extra Points About Stored Procedure
1.You can define a procedure with or without formal parameters.
2.A parameter can be either pass-by-value or pass-by-reference.
3.A procedure will be a pass-by-value procedure when you don’t specify the parameter mode because it uses the
default IN mode.
PL/SQL functions and stored procedures are both types of database objects that encapsulate a block of code,
but they serve different purposes:
1. **Return Value:**
- **Function:** A function must return a single value using the `RETURN` statement. It's used in SELECT
statements or within expressions to compute and return a value.
- **Stored Procedure:** A stored procedure doesn't need to return a value. It can perform various
operations, such as inserting, updating, or deleting data, but it doesn't return a result like a function does.
2. **Usage:**
- **Function:** Functions are typically used in SQL statements (SELECT queries) or within expressions,
allowing you to compute and return a value as part of the result set.
- **Stored Procedure:** Stored procedures are used to encapsulate a series of SQL and PL/SQL statements
that perform specific tasks or operations. They can also be called from other PL/SQL code or even from
outside the database.
3. **Calling:**
- **Function:** Functions can be called directly within SQL statements or expressions.
- **Stored Procedure:** Stored procedures are usually called using the `CALL` statement or within other
PL/SQL blocks.
When defining parameters for PL/SQL functions and procedures, you can specify different parameter modes
to indicate how the parameters are used within the function or procedure. The available parameter modes are:
1. **IN:**
- This is the default mode if you don't specify a mode.
- An `IN` parameter allows you to pass values into the function or procedure.
- The function or procedure can read and use the value but cannot modify it.
2. **OUT:**
- An `OUT` parameter is used to return a value from a procedure.
- The parameter's value is initially NULL, and the procedure can modify the parameter's value to provide an
output.
- Functions can't have `OUT` parameters since they are expected to return a single value.
3. **IN OUT:**
- An `IN OUT` parameter combines the behavior of both `IN` and `OUT` parameters.
- You can pass a value into the procedure, the procedure can modify the value, and the modified value is
also accessible after the procedure call.
1. **Formal Parameters:**
- Formal parameters are the placeholders you define in the function or procedure header. They define the
names, data types, and modes of the parameters that the function or procedure can accept.
- These parameters serve as variables within the function or procedure block, and you can reference them to
perform operations.
2. **Actual Parameters:**
- Actual parameters are the values you provide when calling a function or procedure.
- They correspond to the formal parameters and provide the data that the function or procedure works with.
- Actual parameters can be constants, variables, expressions, or other function/procedure calls.
In summary, PL/SQL functions return values and are often used in SQL queries, while stored procedures don't
return values and are used to perform tasks. Parameter modes (IN, OUT, IN OUT) dictate how parameters are
used within functions and procedures. Formal parameters are defined in the function/procedure signature,
while actual parameters are the values you pass when calling the function/procedure.
BEGIN
In the above example I have created a PL/SQL Stored procedure with the name MY_NAME which has two
variables capable of holding strings of VARCHAR2 datatype. In the execution section this PL/SQL procedure has
only one DBMS OUTPUT statement which is displaying the strings stored into those variable back to the user in a
formatted manner.
EXECUTE MY_NAME;
Or you can also write the first 4 letters of the EXECUTE keyword followed by the procedure name.
EXEC MY_NAME;
Both the statements are the same and will do the same work.
BEGIN
MY_NAME;
END;
You simply have to write the name of your stored procedure inside the execution section of an anonymous and
named PL/SQL block. The compiler will automatically interpret that as a procedure call statement. If your procedure
accepts any parameters then you can supply values for parameters here.
The header is pretty similar to the one which we saw in the last section except that this time our procedure is
accepting parameters which are dep_id and sal_raise of NUMBER datatype.
BEGIN
UPDATE employees SET salary = salary * sal_raise WHERE department_id = dep_id;
END;
/
For a better understanding I have tried to make this code as simple as possible. In the execution section we only
have one DML statement which is UPDATE. Using this we update the salary column of employee table.
You can write the business logic like this then wrap them up into a procedure and call them in your app when
needed. This will give you more control on your app. It will also save you from writing the same code again
and again.
This procedure will accept two parameters which is the department id and the numeric value for salary raise.
First parameter which is the dep_id, is used to determine the ID of the department. The second parameter which
is sal _ raise will become the multiplication factor in the salary raise.
Let’s combine all the above chunks of code into a single one named PL/SQL unit.
EXECUTE emp_sal(201,1.07);
This is the header of the PL/SQL Function which we saw in How to Create Functions in Oracle
Database. Here the parameter radius NUMBER is the formal parameter.
Actual parameters are the parameters which you specify when you call the subroutine such as
Functions or Procedures. These are actually the values you provide to the subroutine when you call
them. You can call a subroutine without an actual parameter when the formal parameter has a default
value.
Always make sure that the datatype of the value you specified as an actual parameter must match with
the data type of the corresponding formal parameter. Also, the value specified as an actual parameter
of a function will override the default value of the corresponding formal parameter if it has any.
1. Positional Notation
2. Named Notation and
3. Mixed calling notation
Positional notation is the most common calling notation which you can see in almost every computer
programming language. In positional notation we have to specify the value for each formal parameter in a
sequential manner. This means that you have to provide the values for the formal parameters in the same order
as they were declared in the procedure or in the function.
In positional notation the datatype and the position of the actual parameter must match with the formal
parameter.
This is the same example which we did in previous section on how to create stored procedure with parameters
albeit some minor changes. Now if we use positional calling notation then we have to supply the values to both
the parameters of the above procedure in the same manner in which they are declared.
Stored Procedure call using positional notation in Oracle Database
EXECUTE emp_sal(40,2);
In this simple procedure call, the value 40 is corresponding to the formal parameter dep_id and value 2 is
corresponding to the parameter sal_raise.
This calling notation is useful when you have a subroutine with parameters where some of those parameters are
mandatory and some are optional and you want to pass the values to only the mandatory ones.
Association Operator
In order to assign values to the formal parameters using their names we use association operator. It is a
combination of equal to (=) sign and greater than (>) sign. We write the name of the formal parameter to the
left hand side of the operator and the value which you want to assign to the right hand side of the operator.
The above function has 3 parameters. Among these 3 parameters 2 are mandatory and 1 is optional with a
default value 0.
You can call this function using positional notation. But it has a restriction which you have to fulfill and that is
that you have to supply values to all the formal parameters in the same order in which they are declared and the
datatype of formal and actual parameters must match.
So if you want to omit the optional parameter and want to use their default value or you just forgot the order of
the parameter in which they were declared! Then it will be slightly difficult for you to call the above subroutine
using positional notation. In such a scenario you can take advantage of Named Calling Notation. This calling
notation will provide you the desired flexibility in calling your subroutines.
NUM_1 = 5
NUM_2 = 0
NUM_3 = 4
9
NUM_1 = 10
NUM_2 = 0
NUM_3 = 4
14
Stored Procedures
PL/SQL Functions
Database Cursors
Type declarations as well as
Variables
Info
All the objects included into a package are collectively called Package Elements.
Package Architecture
PL/SQL package is divided into two parts:
Both these parts are stored separately in the data dictionary. The package specification is the required part
whereas the package body is optional, but it is a good practice to provide the body to the package.
1.Package Specification
Package specification is also known as the package header. It is the section where we put the declaration of all
the package elements. Whatever elements we declare here in this section are publicly available and can be
referenced outside of the package.
Info
In this section we only declare package elements but we don’t define them. Also this is the mandatory
section of the package.
2.Package Body
In package body we provide the actual structure to all the package elements which we have already declared in
the specification by programming them. Or we can say that a package body contains the implementation of the
elements listed in the package specification.
Unlike package specification a package body can contain both declaration of the variable as well as the
definition of all the package elements. Any package elements such as PL/SQL Function, a cursor or a stored
procedure which is not in the package specification but coded in the package body is called Private Package
Elements and thus they cannot be referenced outside the package.
Syntax is bit similar to package specification here we added BODY keyword which indicates body of a
package
As we talked while discussing the architecture of the package in the previous sectionthat the package is divided
into two parts, which are
Package header
The package body
Package Header
SET SERVEROUTPUT ON;
CREATE OR REPLACE PACKAGE PKG_HUSSAIN IS
FUNCTION PRINT_STRG RETURN VARCHAR2;
PROCEDURE PROCE_SUPERHERO (FIRST_NAME VARCHAR2, LAST_NAME VARCHAR2);
END PKG_HUSSAIN;
/
By taking a look at the above code we can clearly say that the package is going to hold two package elements
which are – a PL/SQL function PRINT_STRG and a stored procedure PROCE_SUPERHERO.
Package Body
CREATE OR REPLACE PACKAGE BODY PKG_HUSSAIN IS
--Function Implimentation
FUNCTION PRINT_STRG RETURN VARCHAR2 IS
BEGIN
RETURN 'HI THIS IS HUSSAIN FROM FSF LEVEL2 TEAM';
END PRINT_STRG;
--Procedure Implimentation
PROCEDURE PROCE_SUPERHERO (FIRST_NAME VARCHAR2, LAST_NAME VARCHAR2)IS
BEGIN
INSERT INTO SUPER_HEROS(F_NAME,L_NAME) VALUES (FIRST_NAME,LAST_NAME);
END;
END PKG_HUSSAIN;
/
In the above code for the package body we implemented both the package elements which we defined into the
package header.
Info
Both package header and body are individual database objects thus you have to compile them separately in
order to put your package to work.
Example:
For example say you want to call the PL/SQL function print_strg of our package PKG_HUSSAIN.
For example say you want to call the PL/SQL procedure print_strg of our package PKG_HUSSAIN.
What is an Exception?
Any abnormal condition or say event that interrupts the normal flow of your program’s instructions at run time is an
exception. Or in simple words you can say an exception is a run time error.
Info:
Exceptions are designed for run time error handling rather than compile time error handling. Errors that
occur during compilation phase are detected by the PL/SQL compiler and reported back to the user.
Types of exceptions
There are two types of PL/SQL exceptions in Oracle database.
System-Defined Exceptions
System-defined exceptions are defined and maintained implicitly by the Oracle server. These exceptions are mainly
defined in the Oracle STANDARD package. Whenever an exception occurs inside the program. The Oracle server
matches and identifies the appropriate exception from the available set of exceptions.
System defined exceptions majorly have a negative error code and error message. These errors have a short name
which is used with the exception handler.
Info:
Oracle avails two utility functions SQLCODE & SQLERRM to retrieve the error code and message for last
occur exception.
User-Define Exceptions
Unlike System-Define Exception, User-Define Exceptions are raised explicitly in the body of the PL/SQL block
(more specifically inside the BEGIN-END section) using the RAISE Statement.
You can declare a user defined exception by declaring a variable of EXCEPTION datatype in your code and
raise it explicitly in your program using RAISE statement and handle them in the Exception Section.
3. RAISE_APPLICATION_ERROR method.
Using this method you can declare a user defined exception with your own customized error number and
message.
For the demonstration purpose I will write a code which will check whether the divisor is zero or not in the
division operation. If it is zero then an error will occur and will be displayed to the user otherwise an actual
value which is the result of the division arithmetic will be returned on the output screen.
DECLARE
VAR_DIVIDEND NUMBER := '&PROVIDE_DIVIDEND';
VAR_DIVISOR NUMBER := '&PROVIDE_DIVIDEND';
VAR_RESULT NUMBER;
EXCEPTION_VAR EXCEPTION;
In this declaration section we have 4 variables. Among these 4 variables first 3 are normal Number datatype
variables and the 4th one which is EXCEPTION_VAR is the special EXCEPTION datatype variable. This
variable will become our User-Define Exception for this program.
Raise statement is a special kind of PL/SQL statement which changes the normal flow of execution of the code.
As soon as compiler comes across a raise condition it transfers the control over to the exception handler.
BEGIN
IF VAR_DIVISOR = 0 THEN
RAISE EXCEPTION_VAR;
END IF;
Here raise condition is accompanied with the IF-THEN condition. With the help of this we can avoid unwanted
switches during the control flow of the program. Using If Condition we are making sure that this error will
come into action only when the divisor is equal to 0.
VAR_RESULT :=VAR_DIVIDEND/VAR_DIVISOR;
DBMS_OUTPUT.PUT_LINE('RESULT = '||VAR_RESULT);
After writing the logic for raising the error you can write your other executable statements of the code just like
we did here. After the Raise statement we are performing the arithmetic of division operation and storing the
result into the variable VAR_RESULT, as well as displaying it back as the output using the DBMS OUTPUT
statement.
Here we have the exception handler for the variable EXCEPTION_VAR. In the exception handling section we
have a DBMS OUTPUT statement which will get displayed when our user define error which is
EXCEPTION_VAR occurs.
VAR_RESULT :=VAR_DIVIDEND/VAR_DIVISOR;
DBMS_OUTPUT.PUT_LINE('RESULT = '||VAR_RESULT);
EXCEPTION WHEN EXCEPTION_VAR THEN
DBMS_OUTPUT.PUT_LINE('Error Error - Your Divisor is Zero');
END;
/
RESULT = 5
VAR_RESULT :=VAR_DIVIDEND/VAR_DIVISOR;
DBMS_OUTPUT.PUT_LINE('RESULT = '||VAR_RESULT);
EXCEPTION WHEN EXCEPTION_VAR THEN
DBMS_OUTPUT.PUT_LINE('Error Error - Your Divisor is Zero');
END;
procedure?
RAISE_APPLICATION_ERROR procedure allows us to number our errors from -20,000 to -20,999 thus we
can say that using RAISE_APPLICATION_ERROR procedure we can generate 1000 errors.
Syntax of Raise_Application_Error
Here the error_number is a negative integer in the range of -20000.. -20999 and the message is a character
string up to 2048 bytes long. In case of the optional third parameter being TRUE, the error is placed on the pile
of all the previous errors. However in case of FALSE (the default) parameter, the error replaces all previous
errors. RAISE_APPLICATION_ERROR is part of package DBMS_STANDARD, and you do not need to
qualify references to package STANDARD.
Optional Parameter: There's another thing you can add if you want. It's like an extra option. If you set it
to "TRUE," the error you're raising will be added to a list of previous errors. If you set it to "FALSE"
(which is the default), the new error will replace any previous errors.
In the following example we will take an input of numeric datatype from the user and check if it is 18 or above.
If it is not then the user-define error, which we will declare, will be raised otherwise there will be the normal
flow of execution of the program.
Command starts with the keyword accept followed by the name of the variable and its datatype. In our case the
name is var_age and datatype is NUMBER. That is the first half of the statement. This part will help us in
storing the input value. The other half of the statement will be responsible for printing the customized message
on the pop-up box. Using the keyword PROMPT which is right after the datatype of the variable, you can
specify any desired string which you want printed on your pop-up box. In our case this customized message
will be ‘What is your age?’
Due to the scope restriction we cannot use the value stored into the variable which we used in the accept
command. This means we cannot directly use that value into our PL/SQL program. We can solve this problem
by assigning the value that was stored into the variable var_age to a variable which is local to the PL/SQL
block. That is exactly what we did in the above segment of the code.
Here in this code segment we declared the user-define exception using RAISE_APPLICATION_ERROR
procedure. This procedure is called using two parameters. In which first parameter is the negative number
which, in my case, is -20008 and the second number is a string which gets displayed if the same error occurs.
As you can see that the code is enclosed inside an IF-THEN conditional control block which is making sure
that the error will be raised only if the age of the user is less than 18 years.
Executable statements are those that get compiled and run when there is no error and the program has a normal flow
of execution. In order to make the code simple and easy to understand I just wrote a single statement which is the
DBMS OUTPUT statement.
PRAGMA Keyword
A pragma is a compiler directive which indicates that the Statements followed by keyword PRAGMA is a
compiler directive statement this means that the statement will be processed at the compile time & not at the
runtime.
In summary, compilation is the preparation step where the code is transformed into a
machine-readable format, and execution (running) is the actual step where the computer
carries out the instructions specified in the code.
PRAGMA Exception_Init
Exception_init helps you in associating an exception name with an Oracle error number. In other words we can
say that using Exception_Init you can name the exception.
Now think that in your project you have multiple exceptions and that too without name. In order to handle all
those exceptions you have a single exception handler with name OTHERS. In this case on the occurrence of an
exception condition the compiler will display the error stack produced by the OTHER handler.
Can you imagine how difficult it will be to trace that part of your project which is causing the error. In order to
trace that part you need to go through each & every line of your code. This will be mere waste of time.
You can save all those time wasting efforts just by naming the exception, that way you can design an exception
handler specific to the name of your exception which will be easily traceable. This is the advantage of naming
the exception.
Syntax of Pragma Exception_Init.