UNIT V PLSQL
UNIT V PLSQL
PL/SQL
INTRODUCTION
PL/SQL (Procedural Language/Structured Query Language) is a block-
structured language developed by Oracle that allows developers to combine
the power of SQL with procedural programming constructs.
Basics of PL/SQL
PL/SQL stands for Procedural Language extensions to the
Structured Query Language (SQL).
PL/SQL is a combination of SQL along with the procedural features
of programming languages.
Oracle uses a PL/SQL engine to process the PL/SQL statements.
PL/SQL includes procedural language elements like conditions and
loops. It allows declaration of constants and variables, procedures
and functions, types and variable of those types and triggers.
Features of PL/SQL
1. PL/SQL is basically a procedural language, which provides the
functionality of decision-making, iteration, and many more features
of procedural programming languages.
2. PL/SQL can execute a number of queries in one block using single
command.
3. One can create a PL/SQL unit such as procedures, functions,
packages, triggers, and types, which are stored in the database for
reuse by applications.
4. PL/SQL provides a feature to handle the exception which occurs in
PL/SQL block known as exception handling block.
5. Applications written in PL/SQL are portable to computer hardware
or operating system where Oracle is operational.
6. PL/SQL Offers extensive error checking.
Differences Between SQL and PL/SQL
SQL PL/SQL
Typically, each block performs a logical action in the program. A block has
the following structure:
DECLARE
declaration statements;
BEGIN
executable statements
EXCEPTIONS
exception handling statements
END;
Declare section starts with DECLARE keyword in which variables,
constants, records as cursors can be declared which stores data
temporarily. It basically consists definition of PL/SQL identifiers.
This part of the code is optional.
Execution section starts with BEGIN and ends with END keyword.
This is a mandatory section and here the program logic is written to
perform any task like loops and conditional statements. It supports
all DML commands, DDL commands and SQL*PLUS built-in
functions as well.
Exception section starts with EXCEPTION keyword. This section is
optional which contains statements that are executed when a run-
time error occurs. Any exceptions can be handled in this section.
PL/SQL Identifiers
SQL> DECLARE
var1 INTEGER;
var2 REAL;
var3 varchar2(20) ;
BEGIN
null;
END;
/
1. Output:
PL/SQL procedure successfully completed.
1. Explanation:
SET SERVEROUTPUT ON: It is used to display the buffer
used by the dbms_output.
var1 INTEGER : It is the declaration of variable,
named var1 which is of integer type. There are many other data
types that can be used like float, int, real, smallint, long etc. It
also supports variables used in SQL as well like
NUMBER(prec, scale), varchar, varchar2 etc.
PL/SQL procedure successfully completed.: It is displayed
when the code is compiled and executed successfully.
Slash (/) after END;: The slash (/) tells the SQL*Plus to execute
the block.
Assignment operator (:=) : It is used to assign a value to a
variable.
2. Displaying Output: The outputs are displayed by using
DBMS_OUTPUT which is a built-in package that enables the user to
display output, debugging information, and send messages from
PL/SQL blocks, subprograms, packages, and triggers. Let us see an
example to see how to display a message using PL/SQL :
SQL> SET SERVEROUTPUT ON;
SQL> DECLARE
var varchar2(40) := 'MRCAS' ;
BEGIN
dbms_output.put_line(var);
END;
/
1. Output:
MRCAS
SQL> DECLARE
BEGIN
null;
END;
/
1. Output:
Enter value for a: 24
old 2: a number := &a;
new 2: a number := 24;
Enter value for b: 'HAI'
old 3: b varchar2(30) := &b;
new 3: b varchar2(30) := 'HAI';
Output
Explanation: In the above Query, We have declares a variable named
"name" with a size of 20 characters and initializes it with the
value GeeksForGeeks then prints the value of the variable
using DBMS_OUTPUT.PUT_LINE.
2. Using Initializing Variables in PL/SQL
In this method Variables can be initialized in two ways either during
declaration or later in the code.
a. Initializing during declaration
Variables can be assigned values when declared, as shown below:
Syntax:
DECLARE
my_variable NUMBER := value;
BEGIN
-- PL/SQL code
END;
Example:
DECLARE
name VARCHAR2(20) := 'GeeksForGeeks';
BEGIN
DBMS_OUTPUT.PUT_LINE(name);
END;
Output:
DECLARE
v_number NUMBER;
BEGIN
-- Using := for assignment
v_number := 100; -- Correct (Assigning value to variable)
Incorrect Usage:
DECLARE
v_number NUMBER;
BEGIN
IF v_number := 100 THEN -- Incorrect! := cannot be used for
comparison
DBMS_OUTPUT.PUT_LINE('This will cause an error');
END IF;
END;
/
This will cause an error because := is meant for assignment, not for logical
conditions.
Arithmetic Operators
For example,
Assume variable A holds 10 and variable B holds 5,
Operato
Description Example
r
+ Adds two operands A + B will give 15
begin
if condition then
dbms_output.put_line('output');
end if;
dbms_output.put_line('output2');
end;
begin
end;
As the condition present in the if statement is false. So, the block below the
if statement is not executed. Output:
I am Not in if
2. IF THEN ELSE
The if statement alone tells us that if a condition is true it will execute a
block of statements and if the condition is false it won’t. But what if we
want to do something else if the condition is false. Here comes the else
statement. We can use the else statement with if statement to execute a
block of code when the condition is false.
Syntax:-
if (condition) then
-- Executes this block if
-- condition is true
else
-- Executes this block if
-- condition is false
Example:-
-- pl/sql program to illustrate If else statement
declare
num1 number:= 10;
num2 number:= 20;
begin
ELSE
dbms_output.put_line('i am in else Block');
end if;
begin
if num1 < num2 then
dbms_output.put_line('num1 small num2');
end if;
Example:-
-- pl/sql program to illustrate if-then-elif-then-else ladder
declare
num1 number:= 10;
num2 number:= 20;
begin
if num1 < num2 then
dbms_output.put_line('num1 small');
ELSE
dbms_output.put_line('num2 greater');
end if;
WHILE LOOP
A WHILE LOOP statement in PL/SQL programming language repeatedly
executes a target statement as long as a given condition is true.
Syntax
WHILE condition LOOP
sequence_of_statements
END LOOP;
Example
DECLARE
a number(2) := 10;
BEGIN
WHILE a < 20 LOOP
dbms_output.put_line('value of a: ' || a);
a := a + 1;
END LOOP;
END;
/
When the above code is executed at the SQL prompt, it produces the
following result −
value of a: 10
value of a: 11
value of a: 12
value of a: 13
value of a: 14
value of a: 15
value of a: 16
value of a: 17
value of a: 18
value of a: 19
FOR LOOP
Nested Blocks
Variable Scope
Outer block variables are accessible in the inner block unless re-
declared (shadowed).
Inner block variables are not accessible in the outer block.
Example
DECLARE
outer_x NUMBER := 10; -- Outer block variable
BEGIN
DBMS_OUTPUT.PUT_LINE('Outer Block x: ' || outer_x);
DECLARE
inner_x NUMBER := 20; -- Inner block variable (different name)
BEGIN
DBMS_OUTPUT.PUT_LINE('Inner Block x: ' || inner_x);
DBMS_OUTPUT.PUT_LINE('Accessing Outer Block x: ' || outer_x);
-- Direct access
END;
DECLARE
x NUMBER := 10; -- Outer block variable
BEGIN
DBMS_OUTPUT.PUT_LINE('Outer Block x: ' || x);
Outer Block x: 10
Inner Block x: 20
Accessing Outer Block x: 10
Outer Block x After Inner Block: 10
Inner Block
Case Outer Block Variable Access
Variable
Without Conflicts No conflict, both
Directly accessible
(Different Names) accessible
With Conflicts (Same Shadows outer Use labeled blocks
Name) variable (<<outer_block>>.x)
SQL in PLSQL
PL/SQL allows embedding SQL statements (DML, DDL, and queries)
within its blocks for efficient database interaction.
Data Manipulation
PL/SQL supports INSERT, UPDATE, DELETE, and SELECT statements
within a block.
DECLARE
v_emp_id NUMBER := 101;
v_salary NUMBER := 50000;
BEGIN
-- Insert a new record
INSERT INTO employees (emp_id, salary) VALUES (v_emp_id,
v_salary);
Explanation
SELECT…INTO is used when fetching one row.
If no data is found, it raises NO_DATA_FOUND exception.
TCL Statements
Command Description
COMMIT Saves all changes permanently
ROLLBACK Undoes changes since last commit
SAVEPOINT Marks a point to which a transaction can be rolled back
BEGIN
INSERT INTO employees (emp_id, emp_name, salary) VALUES (101,
'John', 50000);
UPDATE employees SET salary = 55000 WHERE emp_id = 101;
DBMS_OUTPUT.PUT_LINE('Transaction Committed');
END;
/
Explanation
Data is saved permanently.
No rollback is possible after COMMIT.
BEGIN
INSERT INTO employees (emp_id, emp_name, salary) VALUES (102,
'Alice', 60000);
-- Simulating an error
ROLLBACK; -- Undo the INSERT operation
Explanation:
ROLLBACK TO sp2; undoes only the DELETE but keeps the
UPDATE.
Final COMMIT saves all remaining changes.
Implicit Cursors
Implicit cursors are automatically created by Oracle whenever an SQL
statement is executed, when there is no explicit cursor for the statement.
Programmers cannot control the implicit cursors and the information in it.
Whenever a DML statement (INSERT, UPDATE and DELETE) is issued,
an implicit cursor is associated with this statement. For INSERT
operations, the cursor holds the data that needs to be inserted. For
UPDATE and DELETE operations, the cursor identifies the rows that
would be affected.
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 –
%FOUND
Returns TRUE if an INSERT, UPDATE, or DELETE statement
1
affected one or more rows or a SELECT INTO statement returned one
or more rows. Otherwise, it returns FALSE.
%NOTFOUND
The logical opposite of %FOUND. It returns TRUE if an INSERT,
2 UPDATE,
or 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.
Example
The following program will update the table and increase the salary of each
customer by 500 and use the SQL%ROWCOUNT attribute to determine
the number of rows affected −
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 −
6 customers selected
If we check the records in customers table, you will find that the rows have
been updated −
+----+----------+-----+-----------+----------+
| ID | NAME | AGE | ADDRESS | SALARY |
+----+----------+-----+-----------+----------+
| 1 | Ramesh | 32 | Ahmedabad | 2500.00 |
| 2 | Khilan | 25 | Delhi | 2000.00 |
| 3 | kaushik | 23 | Kota | 2500.00 |
| 4 | Chaitali | 25 | Mumbai | 7000.00 |
| 5 | Hardik | 27 | Bhopal | 9000.00 |
| 6 | Komal | 22 | MP | 5000.00 |
+----+----------+-----+-----------+----------+
Explicit Cursors
For example −
CURSOR c_customers IS
SELECT id, name, address FROM customers;
Example
Following is a complete example to illustrate the concepts of explicit
cursors
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
Syntax:
For Standard FOR LOOP:
-- Basic FOR LOOP
FOR loop_index IN lower_bound..upper_bound
LOOP
-- Statements to be executed in each iteration
END LOOP;
For Reverse FOR LOOP:
-- FOR LOOP in Reverse
FOR loop_index IN REVERSE lower_bound..upper_bound
LOOP
-- Statements to be executed in each iteration
END LOOP;
Output:
Number: 1
Number: 2
Number: 3
Number: 4
Number: 5
When the session opens a cursor with the FOR UPDATE clause, all rows in
the return set will hold row-level exclusive locks. Other sessions can only
query the rows, but they cannot update, delete, or select with FOR
UPDATE.
Oracle provides the FOR UPDATE clause in SQL syntax to allow the
developer to lock a set of Oracle rows for the duration of a transaction.
Syntax:
DECLARE
CURSOR emp_cur IS
SELECT empno, sal
FROM emp
WHERE deptno = 10
FOR UPDATE; -- This locks the selected rows
v_empno emp.empno%TYPE;
v_sal emp.sal%TYPE;
BEGIN
OPEN emp_cur;
LOOP
FETCH emp_cur INTO v_empno, v_sal;
EXIT WHEN emp_cur%NOTFOUND;
END LOOP;
CLOSE emp_cur;
COMMIT;
DECLARE
CURSOR emp_cur IS
SELECT empno, sal FROM emp
WHERE deptno = 10
FOR UPDATE;
v_sal emp.sal%TYPE;
v_empno emp.empno%TYPE;
BEGIN
OPEN emp_cur;
LOOP
FETCH emp_cur INTO v_empno, v_sal;
EXIT WHEN emp_cur%NOTFOUND;
END LOOP;
CLOSE emp_cur;
GFG cursor is initialized with a parameter to retrieve the Id, name, and
rank of Geek from the Geeks Table. The requested data must satisfy the
specified condition.
SET SERVEROUTPUT ON;
DECLARE
CURSOR GFG (Min_rank NUMBER) IS
SELECT Id, name, rank
FROM Geeks
WHERE rank > Min_rank;
-- Declare variables
cur_id Geeks.Id%TYPE;
cur_name Geeks.name%TYPE;
cur_rank Geeks.rank%TYPE;
BEGIN
-- Open and fetch data using the cursor
OPEN GFG(951);
LOOP
FETCH GFG INTO cur_id, cur_name, cur_rank;
EXIT WHEN GFG%NOTFOUND;
-- Process fetched data
DBMS_OUTPUT.PUT_LINE('ID: ' || cur_id || ', Name: ' || cur_name ||
', Rank: ' || cur_rank);
-- Close the loop
END LOOP;
-- Close the cursor
CLOSE GFG;
END;
Output:
Table
Output:
Output
Explanation:
SET SERVEROUTPUT ON is used to display output from
DBMS_OPTPUT.PUT_LINE. GFG cursor and variables are declared in
the declaration block.
Data from the table is checked against the condition mentioned in the
cursor. DBMS_OUTPUT.PUT_LINE to display the data that satisfies the
condition. END LOOP breaks the loop and the cursor is closed using
the CLOSE keyword. The END keyword is used to end the execution.
Syntax:
DECLARE
declare variables;
create a cursor with default value for parameter;
BEGIN OPEN cursor;
FETCH cursor;
process the rows;
CLOSE cursor;
END;
GFG cursor is initialized with a default value for the parameter to retrieve
the Id, name, and rank of Geek from the Geeks Table. The requested data
must satisfy the specified condition mentioned in the cursor.
Explanation: The example mentioned is the same as the one used earlier. In
this example, default values are used in the parameterized cursor.
In DECLARE block cursor is defined with default value for the
parameter . The cursor is called without argument in the BEGIN section.
Important Points About PL/SQL Parameterized Cursors
Explicitly close cursors to free up memory resources.
Use the %NOTFOUND attribute to exit loops when no more rows are
available.
PL/SQL Cursors with Parameters allows for specific actions to be taken
based on parameterized cursor outcomes.
You can adapt the cursor's behavior based on different input values.
Query:
-- Sample Data
CREATE TABLE employees (
employee_id INT PRIMARY KEY,
employee_name VARCHAR(50)
);
INSERT INTO employees VALUES (1, 'John Doe');
INSERT INTO employees VALUES (2, 'Jane Smith');
-- Close Cursor
CLOSE cursor_variable;
END;
/
Output:
Employee
ID Employee Name
1 John Doe
2 Jane Smith
Explanation:
The cursor variable cursor_variable is dynamically opened for the
query 'SELECT * FROM employees'.
The loop fetches and displays the data from the result set.
Exceptions in PL/SQL
An exception is an error condition during a program execution. PL/SQL
supports programmers to catch such conditions using EXCEPTION block
in the program and an appropriate action is taken against the error
condition. There are two types of exceptions −
System-defined exceptions
User-defined exceptions
DECLARE
<declarations 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 a 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;
DBMS_OUTPUT.PUT_LINE ('Name: '|| c_name);
DBMS_OUTPUT.PUT_LINE ('Address: ' || c_addr);
EXCEPTION
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 the SQL prompt, it produces the
following result −
No such customer!
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 the EXCEPTION block.
Raising Exceptions
User-defined Exceptions
PL/SQL allows you to define your own exceptions according to the need of
your program. A user-defined exception must be declared and then raised
explicitly, using either a RAISE statement or the
procedure DBMS_STANDARD.RAISE_APPLICATION_ERROR.
DECLARE
my-exception EXCEPTION;
Example
The following example illustrates the concept. This program asks for a
customer ID, when the user enters an invalid ID, the exception invalid_id is
raised.
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 the 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!
Pre-defined Exceptions
Just Review the below pre defined exceptions : (any four or five u write in
exam)
It is raised when
duplicate values are
DUP_VAL_ON_INDEX 00001 -1 attempted to be stored
in a column with
unique index.
It is raised when
attempts are made to
make a cursor
INVALID_CURSOR 01001 -1001 operation that is not
allowed, such as
closing an unopened
cursor.
It is raised when a
program attempts to
LOGIN_DENIED 01017 -1017 log on to the database
with an invalid
username or password.
It is raised when a
SELECT INTO
NO_DATA_FOUND 01403 +100
statement returns no
rows.
It is raised when a
database call is issued
NOT_LOGGED_ON 01012 -1012 without being
connected to the
database.
It is raised when a
cursor fetches value in
ROWTYPE_MISMATCH 06504 -6504 a variable having
incompatible data
type.
It is raised when a
member method is
invoked, but the
SELF_IS_NULL 30625 -30625
instance of the object
type was not
initialized.
It is raised when
PL/SQL ran out of
STORAGE_ERROR 06500 -6500
memory or memory
was corrupted.
It is raised when a
SELECT INTO
TOO_MANY_ROWS 01422 -1422
statement returns
more than one row.
It is raised when an
arithmetic, conversion,
VALUE_ERROR 06502 -6502 truncation, or
sizeconstraint error
occurs.
It is raised when an
attempt is made to
ZERO_DIVIDE 01476 1476
divide a number by
zero.