PLSQL
PLSQL
UNIT III
INTRODUCTION
PL/SQL is a combination of SQL along with the procedural features of programming languages.
It was developed by Oracle Corporation in the early 90's to enhance the capabilities of SQL.
PL/SQL is one of three key programming languages embedded in the Oracle Database, along
with SQL itself and Java.
The PL/SQL programming language was developed by Oracle Corporation in the late 1980s as
procedural extension language for SQL and the Oracle relational database. Following are
certain notable facts about PL/SQL −
PL/SQL which is a block-structured language; this means that the PL/SQL programs are divided and
written in logical blocks of code. Each block consists of three sub-parts −
1. Declarations
This section starts with the keyword DECLARE. It is an optional section and defines all variables,
cursors, subprograms, and other elements to be used in the program.
2. Executable Commands
This section is enclosed between the keywords BEGIN and END and it is a mandatory section. It consists
of the executable PL/SQL statements of the program. It should have at least one executable line of
code, which may be just a NULL command to indicate that nothing should be executed.
3. Exception Handling
This section starts with the keyword EXCEPTION. This optional section contains exception(s) that
handle errors in the program.
Every PL/SQL statement ends with a semicolon (;). PL/SQL blocks can be nested within other PL/SQL
blocks using BEGIN and END. Following is the basic structure of a PL/SQL block −
DECLARE
<declarations section>
BEGIN
<executable command(s)>
EXCEPTION
<exception handling>
END;
Numeric
Numeric values on which arithmetic operations are performed.
1
Character
Alphanumeric values that represent single characters or strings of characters.
2
Boolean
Logical values on which logical operations are performed.
3
Datetime
4
Dates and times
S.No Data Type & Description
PLS_INTEGER
1 Signed integer in range -2,147,483,648 through 2,147,483,647, represented
in 32 bits
BINARY_INTEGER
2 Signed integer in range -2,147,483,648 through 2,147,483,647, represented
in 32 bits
3 BINARY_FLOAT
Single-precision IEEE 754-format floating-point number
4 BINARY_DOUBLE
Double-precision IEEE 754-format floating-point number
NUMBER(prec, scale)
5 Fixed-point or floating-point number with absolute value in range 1E-130 to
(but not including) 1.0E126. A NUMBER variable can also represent 0
6 DEC(prec, scale)
ANSI specific fixed-point type with maximum precision of 38 decimal digits
7 DECIMAL(prec, scale)
IBM specific fixed-point type with maximum precision of 38 decimal digits
8 NUMERIC(pre, secale)
Floating type with maximum precision of 38 decimal digits
DOUBLE PRECISION
9 ANSI specific floating-point type with maximum precision of 126 binary
digits (approximately 38 decimal digits)
FLOAT
10 ANSI and IBM specific floating-point type with maximum precision of 126
binary digits (approximately 38 decimal digits)
11 INT
ANSI specific integer type with maximum precision of 38 decimal digits
INTEGER
12 ANSI and IBM specific integer type with maximum precision of 38 decimal
digits
SMALLINT
13 ANSI and IBM specific integer type with maximum precision of 38 decimal
digits
REAL
14 Floating-point type with maximum precision of 63 binary digits
(approximately 18 decimal digits)
DECLARE
num1 INTEGER;
num2 REAL;
num3 DOUBLE
PRECISION;
BEGIN
null;
END;
/
VARIABLE
PL/SQL variables must be declared in the declaration section or in a package as a global variable. When
you declare a variable, PL/SQL allocates memory for the variable's value and the storage location is
identified by the variable name.
Where, variable_name is a valid identifier in PL/SQL, datatype must be a valid PL/SQL data type
Some valid variable declarations along with their definition are shown below −
Value of f: 23.333333333333333333
PL/SQL allows the nesting of blocks, i.e., each program block may contain another inner block. If a variable is
declared within an inner block, it is not accessible to the outer block. However, if a variable is declared and
accessible to an outer block, it is also accessible to all nested inner blocks. There are two types of variable scope
•Local variables − Variables declared in an inner block and not accessible to outer blocks.
•Global variables − Variables declared in the outermost block or a package.
Following example shows the usage of Local and Global variables in its simple form −
DECLARE
-- Global variables
num1 number := 95;
num2 number := 85;
BEGIN
dbms_output.put_line('Outer Variable num1: ' || num1); Outer Variable num1: 95
dbms_output.put_line('Outer Variable num2: ' || num2); Outer Variable num2: 85
DECLARE
-- Local variables Inner Variable num1: 195
num1 number := 195; Inner Variable num2: 185
num2 number := 185;
BEGIN
dbms_output.put_line('Inner Variable num1: ' || num1);
dbms_output.put_line('Inner Variable num2: ' || num2);
END;
END;
/
Assigning SQL Query Results to PL/SQL Variables
You can use the SELECT INTO statement of SQL to assign values to PL/SQL variables. For each item in
the SELECT list, there must be a corresponding, type-compatible variable in the INTO list. The following
example illustrates the concept. Let us create a table named CUSTOMERS −
CREATE TABLE CUSTOMERS( ID INT NOT NULL, NAME VARCHAR (20) NOT NULL, AGE INT NOT NULL, ADDRESS
CHAR (25), SALARY DECIMAL (18, 2), PRIMARY KEY (ID) );
DECLARE
c_id customers.id%type := 1;
c_name customers.name%type;
c_addr customers.address%type;
c_sal customers.salary%type;
BEGIN
SELECT name, address, salary INTO c_name, c_addr, c_sal FROM customers WHERE id = c_id;
dbms_output.put_line ('Customer ' ||c_name || ' from ' || c_addr || ' earns ' || c_sal);
END;
/
PL/SQL provides the following types of loop to handle the looping requirements.
Basic loop structure encloses sequence of statements in between the LOOP and END
LOOP statements. With each iteration, the sequence of statements is executed and
then control resumes at the top of the loop.
Syntax
LOOP
Sequence of statements;
END LOOP;
When the above code is executed at the SQL prompt, it produces the following
result −
10
20
30
40
50
After Exit x is: 60
PL/SQL procedure successfully completed.
You can use the EXIT WHEN statement instead of the EXIT statement −
DECLARE
x number := 10;
BEGIN
LOOP
dbms_output.put_line(x);
x := x + 10;
Exit WHEN x > 50;
END LOOP;
-- after exit, control resumes here
dbms_output.put_line('After Exit x is: ' || x);
END;
/
PL/SQL - WHILE LOOP Statement
Syntax
WHILE condition LOOP
sequence_of_statements
END LOOP;
DECLARE value of a: 10
a number(2) := 10; value of a: 11
BEGIN value of a: 12
WHILE a < 20 LOOP value of a: 13
dbms_output.put_line('value of a: ' || a); value of a: 14
a := a + 1; value of a: 15
value of a: 16
END LOOP;
value of a: 17
END; value of a: 18
/ value of a: 19
PL/SQL - FOR LOOP Statement
Syntax
value of a: 10
DECLARE value of a: 11
a number(2); value of a: 12
value of a: 13
BEGIN value of a: 14
FOR a in 10 .. 20 LOOP value of a: 15
value of a: 16
dbms_output.put_line('value of a: ' || a); value of a: 17
END LOOP; value of a: 18
END; value of a: 19
value of a: 20
/ PL/SQL procedure successfully completed.
Reverse FOR LOOP Statement
By default, iteration proceeds from the initial value to the final value, generally upward from the lower
bound to the higher bound. You can reverse this order by using the REVERSE keyword. In such case,
iteration proceeds the other way. After each iteration, the loop counter is decremented.
However, you must write the range bounds in ascending (not descending) order. The following program
illustrates this −
value of a: 20
DECLARE value of a: 19
a number(2) ;
value of a: 18
value of a: 17
BEGIN value of a: 16
•The initial step is executed first, and only once. This step allows you to declare and initialize any loop
control variables.
•Next, the condition, i.e., initial_value .. final_value is evaluated. If it is TRUE, the body of the loop is
executed. If it is FALSE, the body of the loop does not execute and the flow of control jumps to the next
statement just after the for loop.
•After the body of the for loop executes, the value of the counter variable is increased or decreased.
•The condition is now evaluated again. If it is TRUE, the loop executes and the process repeats itself
(body of loop, then increment step, and then again condition). After the condition becomes FALSE, the
FOR-LOOP terminates.
The initial_value and final_value of the loop variable or counter can be literals, variables, or
expressions but must evaluate to numbers. Otherwise, PL/SQL raises the predefined exception
VALUE_ERROR.
The initial_value need not be 1; however, the loop counter increment (or decrement) must be 1.
PL/SQL allows the determination of the loop range dynamically at run time.
PL/SQL - Nested Loops
PL/SQL allows using one loop inside another loop. Following section shows a few examples to illustrate the
concept.
LOOP
Sequence of statements1
LOOP
Sequence of statements2
END LOOP;
END LOOP;
PL/SQL subprograms are named PL/SQL blocks that can be invoked with a set of
parameters. PL/SQL provides two kinds of subprograms −
•Functions − These subprograms return a single value; mainly used to compute and return a
value.
•Procedures − These subprograms do not return a value directly; mainly used to perform an
action.
Creating a Procedure
When the above code is executed using the SQL prompt, it will produce the following result −
Procedure created.
The above procedure named 'greetings' can be called with the EXECUTE keyword as −
EXECUTE greetings;
The procedure can also be called from another PL/SQL block −
BEGIN
greetings;
END; /
You can drop the greetings procedure by using the following statement −
OUT
An OUT parameter returns a value to the calling program. Inside the subprogram, an OUT parameter acts like a variable.
2 You can change its value and reference the value after assigning it. The actual parameter must be variable and it is
passed by value.
IN OUT
An IN OUT parameter passes an initial value to a subprogram and returns an updated value to the caller. It can be assigned
a value and the value can be read.
3 The actual parameter corresponding to an IN OUT formal parameter must be a variable, not a constant or an expression.
Formal parameter must be assigned a value. Actual parameter is passed by value.
This program finds the minimum of two values. Here, the procedure takes two numbers using the IN mode
and returns their minimum using the OUT parameters.
DECLARE
a number;
b number;
c number;
BEGIN
a:= 23;
b:= 45;
findMin(a, b, c);
dbms_output.put_line(' Minimum of (23, 45) : ' || c);
END; /
This procedure computes the square of value of a passed value. This example shows how we can use the same parameter to accept a value
and then return another result.
DECLARE
a number;
BEGIN
x := x * x;
END;
BEGIN
a:= 23;
squareNum(a);
dbms_output.put_line(' Square of (23): ' || a);
END; /
Creating a Function
Where,
CREATE [OR REPLACE] FUNCTION function_name
•function-name specifies the name of the function.
[(parameter_name [IN | OUT | IN OUT] type [, ...])] •[OR REPLACE] option allows the modification of an existing
RETURN return_datatype function.
{IS | AS} •The optional parameter list contains name, mode and types of
BEGIN < function_body > the parameters. IN represents the value that will be passed from
outside and OUT represents the parameter that will be used to
END [function_name];
return a value outside of the procedure.
•The function must contain a return statement.
•The RETURN clause specifies the data type you are going to
return from the function.
•function-body contains the executable part.
•The AS keyword is used instead of the IS keyword for creating a
standalone function.
The following example illustrates how to create and call a standalone function. This function returns
the total number of CUSTOMERS in the customers table.
We will use the CUSTOMERS table.
RETURN number IS
total number(2) := 0; When the above code is executed using the SQL prompt, it will
produce the following result −
BEGIN
SELECT count(*) into total FROM customers;
RETURN total; Function created.
END;
/
Calling a Function
While creating a function, you give a definition of what the function has to do. To use a function, you will
have to call that function to perform the defined task. When a program calls a function, the program
control is transferred to the called function.
A called function performs the defined task and when its return statement is executed or when the last
end statement is reached, it returns the program control back to the main program.
To call a function, you simply need to pass the required parameters along with the function name and if the
function returns a value, then you can store the returned value. Following program calls the
function totalCustomers from an anonymous block −
DECLARE
c number(2); When the above code is executed at the SQL prompt, it produces the
following result −
BEGIN
c := totalCustomers(); Total no. of Customers: 6 PL/SQL procedure successfully completed.
dbms_output.put_line('Total no. of Customers: ' || c);
END;
/
The following example demonstrates Declaring, Defining, and Invoking a Simple PL/SQL Function that computes and returns the maximum of two values.
DECLARE
a number;
b number;
c number;
When the above code is executed at the SQL prompt, it produces the following result −
Maximum of (23,45): 45 PL/SQL procedure successfully completed.
CURSORS
•Implicit cursors
•Explicit cursors
Implicit Cursors:
In PL/SQL, you can refer to the most recent implicit cursor as the SQL cursor,
which always has attributes such as %FOUND, %ISOPEN, %NOTFOUND,
and %ROWCOUNT.
The SQL cursor has additional
attributes, %BULK_ROWCOUNT and %BULK_EXCEPTIONS, designed for use
with the FORALL statement. The following table provides the description of the
most used attributes −
%NOTFOUND
The logical opposite of %FOUND. It returns TRUE if an INSERT, UPDATE, or
2 DELETE statement affected no rows, or a SELECT INTO statement returned
no rows. Otherwise, it returns FALSE.
%ISOPEN
3 Always returns FALSE for implicit cursors, because Oracle closes the SQL
cursor automatically after executing its associated SQL statement.
%ROWCOUNT
4 Returns the number of rows affected by an INSERT, UPDATE, or DELETE
statement, or returned by a SELECT INTO statement.
Any SQL cursor attribute will be accessed as sql%attribute_name as shown
below in the example.
DECLARE
total_rows number(2);
BEGIN
UPDATE customers
SET salary = salary + 500;
IF sql%notfound THEN
dbms_output.put_line('no customers selected');
ELSIF sql%found THEN
total_rows := sql%rowcount;
dbms_output.put_line( total_rows || ' customers selected ');
END IF;
END;
/
When the above code is executed at the SQL prompt, it produces the following result −
If you check the records in customers table, you will find that the rows have been
updated −
Explicit Cursors
Explicit cursors are programmer-defined cursors for gaining more control over
the context area. An explicit cursor should be defined in the declaration section
of the PL/SQL Block. It is created on a SELECT Statement which returns more
than one row.
Declaring the cursor defines the cursor with a name and the associated SELECT statement.
For example −
CURSOR c_customers IS SELECT id, name, address FROM customers;
OPEN c_customers;
Fetching the Cursor
Fetching the cursor involves accessing one row at a time. For example, we will
fetch rows from the above-opened cursor as follows −
Closing the cursor means releasing the allocated memory. For example, we will close the
above-opened cursor as follows −
CLOSE c_customers;
Example
DECLARE
c_id customers.id%type;
c_name customers.name%type;
c_addr customers.address%type;
CURSOR c_customers is
SELECT id, name, address FROM customers;
BEGIN
OPEN c_customers;
LOOP
FETCH c_customers into c_id, c_name, c_addr;
EXIT WHEN c_customers%notfound;
dbms_output.put_line(c_id || ' ' || c_name || ' ' || c_addr);
END LOOP;
CLOSE c_customers;
END;
/
When the above code is executed at the SQL prompt, it produces the following
result −
1 Ramesh Ahmedabad
2 Khilan Delhi
3 kaushik Kota
4 Chaitali Mumbai
5 Hardik Bhopal
6 Komal MP
Triggers are stored programs, which are automatically executed or fired when some events
occur. Triggers are, in fact, written to be executed in response to any of the following events
Triggers can be defined on the table, view, schema, or database with which the event is
associated.
Benefits of Triggers
Where,
CREATE [OR REPLACE ] TRIGGER trigger_name
•CREATE [OR REPLACE] TRIGGER trigger_name −
{BEFORE | AFTER | INSTEAD OF } Creates or replaces an existing trigger with
{INSERT [OR] | UPDATE [OR] | DELETE} the trigger_name.
•{BEFORE | AFTER | INSTEAD OF} − This specifies
[OF col_name] when the trigger will be executed. The INSTEAD OF
ON table_name [REFERENCING OLD AS o NEW AS n] clause is used for creating trigger on a view.
•{INSERT [OR] | UPDATE [OR] | DELETE} − This
[FOR EACH ROW]
specifies the DML operation.
WHEN (condition) •[OF col_name] − This specifies the column name that
DECLARE will be updated.
•[ON table_name] − This specifies the name of the
Declaration-statements
table associated with the trigger.
BEGIN •[REFERENCING OLD AS o NEW AS n] − This allows
Executable-statements you to refer new and old values for various DML
statements, such as INSERT, UPDATE, and DELETE.
EXCEPTION •[FOR EACH ROW] − This specifies a row-level trigger,
Exception-handling-statements i.e., the trigger will be executed for each row being
affected. Otherwise the trigger will execute just once
END;
when the SQL statement is executed, which is called a
table level trigger.
•WHEN (condition) − This provides a condition for rows
for which the trigger would fire. This clause is valid
only for row-level triggers.
Example
To start with, we will be using the CUSTOMERS table we had created and used in
the previous chapters −
The following program creates a row-level trigger for the customers table that would fire
for INSERT or UPDATE or DELETE operations performed on the CUSTOMERS table. This
trigger will display the salary difference between the old values and new values −
CREATE OR REPLACE TRIGGER display_salary_changes
BEFORE DELETE OR INSERT OR UPDATE ON customers
FOR EACH ROW
WHEN (NEW.ID > 0)
DECLARE
sal_diff number;
BEGIN
sal_diff := :NEW.salary - :OLD.salary;
dbms_output.put_line('Old salary: ' || :OLD.salary);
dbms_output.put_line('New salary: ' || :NEW.salary);
dbms_output.put_line('Salary difference: ' || sal_diff);
END; /
When the above code is executed at the SQL prompt, it produces the
following result −
Trigger created.
The following points need to be considered here −
•OLD and NEW references are not available for table-level triggers, rather you
can use them for record-level triggers.
•If you want to query the table in the same trigger, then you should use the
AFTER keyword, because triggers can query the table or change it again only
after the initial changes are applied and the table is back in a consistent state.
•The above trigger has been written in such a way that it will fire before any
DELETE or INSERT or UPDATE operation on the table, but you can write your
trigger on a single or multiple operations, for example BEFORE DELETE, which
will fire whenever a record will be deleted using the DELETE operation on the
table.
Triggering a Trigger
Let us perform some DML operations on the CUSTOMERS table. Here is one
INSERT statement, which will create a new record in the table −
INSERT INTO CUSTOMERS (ID,NAME,AGE,ADDRESS,SALARY) VALUES (7, 'Kriti', 22, 'HP', 7500.00 );
Because this is a new record, old salary is not available and the above result
comes as null. Let us now perform one more DML operation on the CUSTOMERS
table. The UPDATE statement will update an existing record in the table −
2. AFTER Trigger : AFTER trigger execute after the triggering DML statement (INSERT, UPDATE, DELETE) executed.
Triggering SQL statement is execute as soon as followed by the code of trigger before performing Database operation.
3. ROW Trigger : ROW trigger fire for each and every record which are performing INSERT, UPDATE, DELETE from the
database table. If row deleting is define as trigger event, when trigger file, deletes the five rows each times from the table.
4. Statement Trigger : Statement trigger fire only once for each statement. If row deleting is define as trigger event, when
trigger file, deletes the five rows at once from the table.
1. Before Statement Trigger : Trigger fire only once for each statement before the triggering DML statement.
2. Before Row Trigger : Trigger fire for each and every record before the triggering DML statement.
3. After Statement Trigger : Trigger fire only once for each statement after the triggering DML statement executing.
4. After Row Trigger : Trigger fire for each and every record after the triggering DML statement executing.
Inserting Trigger
An error condition during a program execution is called an exception in PL/SQL. PL/SQL supports
programmers to catch such conditions using EXCEPTION block in the program and an appropriate action
is taken against the error condition.
By Handling the exceptions we can ensure a PL/SQL block does not exit abruptly.
Syntax for Exception Handling The General Syntax for exception handling is as
follows.
Here you can list down as many as exceptions you want to handle.
The default exception will be handled using WHEN others THEN:
DECLARE
<declaration section>
BEGIN
<executable command(s)>
EXCEPTION
<Exception handling goes here>
WHEN exception1 THEN
exception1-handling-statements
WHEN exception2 THEN
exception2-handling-statements
WHEN exception3 THEN
exception3-handling-statements
........
WHEN others THEN
exception3-handling-statements
END;
Example Let us write some simple code to illustrate the concept. We will be using the
CUSTOMERS table:
DECLARE
c_id customers.id%type := 8;
c_name customers.name%type;
c_addr customers.address%type;
BEGIN
SELECT name, address INTO c_name, c_addr
FROM customers
WHERE id = c_id;
The above program displays the name and address of a customer whose ID is given.
Since there is no customer with ID value 8 in our database, the program raises the run-
time exception NO_DATA_FOUND, which is captured in EXCEPTION block.
Raising Exceptions
Exceptions are raised by the database server automatically whenever there is any
internal database error, but exceptions can be raised explicitly by the programmer by
using the command RAISE. Following is the simple syntax of raising an exception:
You can use above syntax in raising Oracle standard exception or any user-defined exception. Next
section will give you an example on raising user-defined exception, similar way you can raise Oracle
standard exceptions as well.
User-defined Exceptions
PL/SQL allows you to define your own exceptions according to the need of your program. A userdefined
exception must be declared and then raised explicitly, using either a RAISE statement or the procedure
DBMS_STANDARD.RAISE_APPLICATION_ERROR.
DECLARE
c_id customers.id%type := &cc_id;
c_name customers.name%type;
c_addr customers.address%type;
-- user defined exception
ex_invalid_id EXCEPTION;
BEGIN
IF c_id <= 0 THEN
RAISE ex_invalid_id;
ELSE
SELECT name, address INTO c_name, c_addr FROM customers WHERE id = c_id;
DBMS_OUTPUT.PUT_LINE ('Name: '|| c_name);
DBMS_OUTPUT.PUT_LINE ('Address: ' || c_addr);
END IF;
EXCEPTION
WHEN ex_invalid_id THEN
dbms_output.put_line('ID must be greater than zero!'); WHEN no_data_found THEN
dbms_output.put_line('No such customer!');
WHEN others THEN
dbms_output.put_line('Error!');
END;
/
When the above code is executed at SQL prompt, it produces the following result:
Enter value for cc_id: -6 (let's enter a value -6)
old 2: c_id customers.id%type := &cc_id;
new 2: c_id customers.id%type := -6;
ID must be greater than zero!
PL/SQL procedure successfully completed