Oracle PLSQL
Oracle PLSQL
Table of Contents
1. Revision History ............................................................................................. 3
2. PL/SQL Engine ............................................................................................... 3
3. Block Structure: ............................................................................................. 4
4. Important PL/SQL Data types: ...................................................................... 5
5. Operators: ....................................................................................................... 5
6. Variables: ........................................................................................................ 5
7. Conditional Statements: ................................................................................ 6
8. Loops: ............................................................................................................. 9
1.1. Simple Loops .............................................................................................................................. 9
1.2. While Loops .............................................................................................................................. 10
1.3. For Loops .................................................................................................................................. 11
1. Exceptions: ................................................................................................... 22
1.1. Predefined exceptions: ............................................................................................................. 22
1.2. User defined exceptions: .......................................................................................................... 25
1.3. Pragma Exception: .................................................................................................................... 26
1.4. Raise Application Errors: .......................................................................................................... 26
2. Procedures: .................................................................................................. 27
2.1. Creating a procedure. ............................................................................................................... 27
2.2. Calling a procedure: .................................................................................................................. 28
2.3. Getting information on procedures: .......................................................................................... 29
2.4. Dropping a procedure: .............................................................................................................. 29
2.5. Viewing Errors of a Procedure: ................................................................................................. 29
4. Packages: ..................................................................................................... 34
4.1. Creating a Package Specification ............................................................................................. 34
4.2. Creating a Package Body ......................................................................................................... 35
4.3. Calling functions and procedures in a Package. ...................................................................... 36
4.4. Getting information on functions and procedures in a package: .............................................. 37
4.5. Dropping a Package: ................................................................................................................ 37
5. Triggers:........................................................................................................ 37
5.1. When a trigger fires:.................................................................................................................. 38
5.2. Set Up for the Example Trigger ................................................................................................ 38
5.3. Creating a trigger ...................................................................................................................... 38
5.4. Getting information on triggers: ................................................................................................ 41
5.5. Disabling and Enabling a Trigger .............................................................................................. 41
5.6. Dropping a trigger ..................................................................................................................... 42
3. Block Structure:
PL/SQL programs are divided up into structures known as blocks, with each block containing
PL/SQL and SQL statements. A PL/SQL block has the following structure:
[DECLARE
declaration_statements
]
BEGIN
executable_statements
[EXCEPTION
exception_handling_statements
]
END;
/
Where
Declaration_statements,declare the variables used in the rest of the PL/SQL block.DECLARE
blocks are optional.
executable_statements are the actual executable statements, which may includeloops,
conditional logic, and so on.
exception_handling_statements are statements that handle any execution errorsthat
mightoccur when the block is run. EXCEPTION blocks are optional.
SET SERVEROUTPUT ON
BEGIN
DBMS_OUTPUT.PUT_LINE('Welcome to PL/SQL Programming');
END;
/
Every statement is terminated by a semicolon (;), and a PL/SQL block is terminated using
theforward slash (/) character.
NUMBER - To store numeric values, its behavior is similar to SQL data type.
VARCHAR2 - To store character or string variables.
DATE - To store Date variables.
BOOLEAN - Boolean value, TRUE, FALSE or NULL is assigned
PLS_INTEGER - Using this data type for counter variables is a good practice and it is quick in
arithmetic calculations.
5. Operators:
6. Variables:
SET SERVEROUTPUT ON
DECLARE
Lc_first_num NUMBER(3) := 10;
Lc_second_num NUMBER(3) := 20;
Lc_sum NUMBER(4) ;
BEGIN
Lc_sum := Lc_first_num + Lc_second_num;
DBMS_OUTPUT.PUT_LINE('Sum of two numbers: '|| Lc_sum);
END;
/
Write a simple PL/SQL program to accept two numeric values and calculate sum.
SET SERVEROUTPUT ON
DECLARE
Lv_first_num NUMBER(3) := &Lv_first_num;
Lv_second_num NUMBER(3) := &Lv_second_num;
Lv_sum NUMBER(4) ;
BEGIN
Lv_sum := Lv_first_num + Lv_second_num;
DBMS_OUTPUT.PUT_LINE('Sum of two numbers: '|| Lv_sum);
END;
/
7. Conditional Statements:
IF, THEN, ELSE, ELSIF, and END IF keywords are used to perform conditional logic and below is a
sample conditional block.
Where,
Condition1 and condition2 are Boolean expressions that evaluate to true or false.statements1,
statements2, and statements3 are PL/SQL statements.
IF condition1
THEN
statements1;
IF Condition4
THEN
Statment4;
END IF;
ELSIF condition2
THEN
IF Condition5
THEN
Statement5;
END IF;
statements2;
ELSE
statements3;
END IF;
BEGIN
IF Lv_first_num>Lv_second_num
THEN
IF Lv_first_num>Lv_third_num
C THEN
A DBMS_OUTPUT.PUT_LINE('Lv_first_num: '||Lv_first_num||' is biggest');
S END IF;
E ELSIF Lv_second_num>Lv_third_num
THEN
s DBMS_OUTPUT.PUT_LINE('Lv_second_num: '||Lv_second_num||' is biggest');
t ELSE
a DBMS_OUTPUT.PUT_LINE('Lv_third_num: '||Lv_third_num||' is biggest');
t END IF;
e END;
m /
e
nt:
CASE statement is also used as conditional statement. Below is the syntax to use CASE
statement.
Write a PL/SQL program to find biggest number among 3 input numbers using CASE
statement.
SET SERVEROUTPUT ON
DECLARE
Lv_first_num NUMBER(3) := &Lv_first_num;
Lv_second_num NUMBER(3) := &Lv_second_num;
Lv_third_num NUMBER(3) :=&Lv_third_num;
CASE WHEN <Condition1> THEN ----------;
BEGIN WHEN <Condition2> THEN ---------;
CASE WHEN (Lv_first_num > Lv_second_num
WHEN <Condition3> AND THEN
Lv_first_num
---------; > Lv_third_num)
THEN dbms_output.put_line ('First number is biggest');
ELSE ----------------------------------------------;
WHEN Lv_second_num >
END CASE; Lv_third_num
THEN dbms_output.put_line('Second number is biggest');
ELSE dbms_output.put_line('Third number is biggest');
END CASE;
END;
/
A simple loop runs until an explicit instruction is given to end the loop. The syntax for a simple
loop is as follows:
LOOP
Statements;
END LOOP;
To exit from the loop, either EXIT or EXIT WHEN statements are used. EXIT statement ends a
loop immediately whereas EXIT WHEN exists loop when specified condition occurs.
SET SERVEROUTPUT ON
DECLARE
Lv_counter PLS_INTEGER := 1;
BEGIN
LOOP
Lv_counter := Lv_counter + 1;
DBMS_OUTPUT.PUT_LINE('Lv_counter value is: '|| Lv_counter);
EXIT;
END LOOP;
END;
/
A WHILE loop runs until a specified condition occurs. The syntax for a WHILE loop is as follows,
WHILE <Condition>
LOOP
Statements;
END LOOP;
SET SERVEROUTPUT ON
DECLARE
Lv_counter PLS_INTEGER := 1;
BEGIN
WHILE Lv_counter<=5
LOOP
DBMS_OUTPUT.PUT_LINE('Lv_counter value is: '|| Lv_counter);
Lv_counter := Lv_counter + 1;
END LOOP;
END;
Here in WHILE, no EXIT statement is used to come out of the loop. If Condition mentioned in
WHILE loop is failed then LOOP is automatically closed.
A FOR loop is executed in predefined number of times . Loop runs based on lower and upper
bounds defined for a loop variable. The loop variable is then incremented or decremented each
time around the loop. Below is the syntax for FOR loops.
SET SERVEROUTPUT ON
BEGIN
FOR idx IN 1..10
LOOP
DBMS_OUTPUT.PUT_LINE('Loop variable is: '||idx);
END LOOP;
END;
/
SET SERVEROUTPUT ON
BEGIN
FOR idx IN REVERSE 1..10
LOOP
DBMS_OUTPUT.PUT_LINE('Loop variable is: '||idx);
END LOOP;
END;
/
9. U
PSK Real-time Institute, Opp. Innovative Multiplex, Marathahalli, Bangalore
Contact No: 9739096158, 9739771750
www.pskinfo.com Page 11
sing SQL statements in PL/SQL:
A SQL statement can be used in a PL/SQL block to retrieve data of a table into local PL/SQL
variables and apply some business logic on those variables based on need.
Write a PL/SQL program to retrieve salary and commission of employee and calculate total
salary.
SET SERVEROUTPUT ON
DECLARE
Lv_salary NUMBER(10);
Lv_comm NUMBER(4);
Lv_tot_sal NUMBER(10);
BEGIN
SELECT salary, commission_pct
INTO Lv_salary, Lv_comm
FROM Employees
WHERE employee_id = &employee_id;
Write a PL/SQL program to retrieve salary and commission of employee and calculate total
salary using anchor data types.
SET SERVEROUTPUT ON
DECLARE
Lv_salary Employees.salary%TYPE;
Lv_comm Employees.commission_pct%TYPE;
Lv_tot_sal Employees.salary%TYPE;
BEGIN
SELECT salary, commission_pct
INTO Lv_salary, Lv_comm
FROM Employees
WHERE employee_id = &employee_id;
Write a PL/SQL program to retrieve salary and commission of employee and calculate total
salary using record data types.
SET SERVEROUTPUT ON
DECLARE
Lv_emp_rec Employees%ROWTYPE;
Lv_tot_sal Employees.salary%TYPE;
BEGIN
SELECT salary, commission_pct
INTO Lv_emp_rec.salary, Lv_emp_rec.commission_pct
FROM Employees
WHERE employee_id = &employee_id;
10. Cursors:
Basically there are 3 types of cursors,
Implicit cursors are automatically opened, processed and closed by oracle and user does
not need to explicitly perform these operations while using implicit cursors. Implicit
cursors are associated with the latest SQL used in PL/SQL program.
In general implicit cursors are not used in business as they are bit difficult to manage.Below
are different cursor attributes using for different purposes.
IF SQL%ISOPEN
THEN
DBMS_OUTPUT.PUT_LINE('Implicit cursor automatically opened');
DBMS_OUTPUT.PUT_LINE('Total number of cursor records: '||SQL%ROWCOUNT);
END IF;
DELETE FROM emp_bkp;
IF SQL%FOUND
THEN
DBMS_OUTPUT.PUT_LINE('Implicit cursor now opened to DELETE statement');
DBMS_OUTPUT.PUT_LINE('Total number of cursor records: '|| SQL%ROWCOUNT);
END IF;
ROLLBACK;
UPDATE emp_bkp set salary = salary+(salary*10/100) where department_id = 90;
IF SQL%FOUND
THEN
DBMS_OUTPUT.PUT_LINE('Implicit cursor now opened to UPDATE statement');
DBMS_OUTPUT.PUT_LINE('Total number of cursor records: '|| SQL%ROWCOUNT);
END IF;
ROLLBACK;
END;
/
Using Cursors multiple rows of a table can be fetched into PL/SQL variables and used to
apply business logic. Cursor fetches one row at a time and processes the data. Cursor
follows below sequence of steps,
Cursors can be operated in SIMPLE LOOPS, WHILE LOOPS and FOR LOOPS.
Write a PL/SQL program to retrieve employee name, salary and commission of employees in a
department and calculate total salary using cursors with SIMPLE loops.
SET SERVEROUTPUT ON
DECLARE
Lv_emp_name Employees.first_name%TYPE;
Lv_salary Employees.salary%TYPE;
Lv_comm Employees.commission_pct%TYPE;
Lv_tot_sal Employees.salary%TYPE;
--Declaration of cursor
CURSOR cur_emp IS
SELECT first_name, salary, commission_pct
FROM Employees
WHERE department_id = &department_id;
BEGIN
OPEN cur_emp; --Opening cursor before fetching data.
LOOP
FETCH cur_emp INTO Lv_emp_name, Lv_salary, Lv_comm;
EXIT WHEN cur_emp%NOTFOUND;
Lv_tot_sal := Lv_salary + NVL(Lv_comm, 0)*Lv_salary;
DBMS_OUTPUT.PUT_LINE('Emp Name: '||Lv_emp_name||' and Total Salary: '||Lv_tot_sal);
END LOOP;
CLOSE cur_emp;
END;
/
Write a PL/SQL program to retrieve employee name, salary and commission of employees in a
department and calculate total salary using cursors with WHILE loop.
Write a PL/SQL program to retrieve employee name, salary and commission of employees in a
department and calculate total salary using cursors with FOR loop.
SET SERVEROUTPUT ON
DECLARE
Lv_tot_sal Employees.salary%TYPE;
BEGIN
FOR emp_rec IN (SELECT first_name, salary, commission_pct
FROM employees WHERE department_id = &department_id)
LOOP
Lv_tot_sal := emp_rec.salary+ NVL(emp_rec.commission_pct, 0)*emp_rec.salary;
DBMS_OUTPUT.PUT_LINE('Emp Name: '||emp_rec.first_name||' and Total Salary: '||Lv_tot_sal);
END LOOP;
END;
/
REF cursors are used to point to various context areas by pointing to different SQL
statements. REF cursors use "OPEN FOR" command to open cursors.
Write a PL/SQL program to retrieve employee name, salary and commission of employees in a
department and calculate total salary using cursors with FOR loop.
SET SERVEROUTPUT ON
DECLARE
Lv_emp_cur SYS_REFCURSOR;
Lv_emp_nameEmployees.first_name%TYPE;
Lv_emp_salEmployees.salary%TYPE;
Lv_emp_commEmployees.commission_pct%TYPE;
Lv_tot_salEmployees.salary%TYPE;
BEGIN
OPEN Lv_emp_cur FOR SELECT first_name, salary, commission_pct
FROM employees WHERE department_id = 90;
LOOP
FETCH Lv_emp_cur INTO Lv_emp_name, Lv_emp_sal, Lv_emp_comm;
EXIT WHEN Lv_emp_cur%NOTFOUND;
Lv_tot_sal := Lv_emp_sal+ NVL(Lv_emp_comm, 0)*Lv_emp_sal;
DBMS_OUTPUT.PUT_LINE('Emp Name: '||Lv_emp_name||' and Total Salary: '||Lv_tot_sal);
END LOOP;
CLOSE Lv_emp_cur;
END;
/
Here in above example, Lv_emp_cursor is pointed to 2 context areas, one for the data of
department_id = 90 and another is data of department_id = 100. Ref cursors are mainly when
there is a possibility of processing data dynamically.
Additional Note:
PSK Real-time Institute, Opp. Innovative Multiplex, Marathahalli, Bangalore
Contact No: 9739096158, 9739771750
www.pskinfo.com Page 17
-- are used for single line comments
/* .....*/ are used for multi-line comments.
Associative arrays are used to list of values in a single variable. It will use index
for each element stored in associative array. Associative arrays are ideal when we does
not know the number items stored in the variable. Associative arrays are does not need
to initiate before using them. This is most commonly used composite data type in real
time scenarios to process bulk records. Index by data type in associate arrays can be a
integer or fixed length string value.
Syntax:
SET SERVEROUTPUT ON
DECLARE
TYPE list_type IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;
list_t list_type;
BEGIN
FOR i IN 1..10
LOOP
list_t(i) := i;
DBMS_OUTPUT.PUT_LINE('Value stored in slot: '||i||' is: '||list_t(i));
END LOOP;
END;
/
SET SERVEROUTPUT ON
DECLARE
Lv_department_id employees.department_id%TYPE := &deptid;
TYPE emp_sal_type IS TABLE OF employees.salary%TYPE INDEX BY
BINARY_INTEGER;
emp_sal_t emp_sal_type;
BEGIN
SELECT salary BULK COLLECT
INTO emp_sal_t
FROM employees
WHERE department_id = Lv_department_id;
FOR i in emp_sal_t.FIRST..emp_sal_t.LAST
LOOP
DBMS_OUTPUT.PUT_LINE('Salary in slot: '||i|| emp_sal_t(i));
END LOOP;
END;
/
Records data types that are used along with Associative arrays:
Syntax:
SET SERVEROUTPUT ON
DECLARE
lv_department_id employees.department_id%TYPE := &deptno;
TYPE emp_rec IS RECORD
(
emp_no employees.employee_id%TYPE,
emp_sal employees.salary%TYPE,
emp_job employees.job_id%TYPE
);
FOR i IN emp_t.FIRST..emp_t.LAST
LOOP
DBMS_OUTPUT.PUT_LINE('Employee id: '||emp_t(i).emp_no||' salary:
'||emp_t(i).emp_Sal||' Job is: '||emp_t(i).emp_job);
END LOOP;
END;
/
2.2. Varrays:
The VARRAY datatype is the most like a traditional array. Elements are of the
same type and use a sequential numeric index. This means the index of VARRAY
variables is densely populated. You opt to use a VARRAY when you know the number of
items that will go in the collection before declaring the variable.
Syntax:
The nested table datatype is the more like a numerically indexed list or Java class. As in
the VARRAY, elements are of the same type and use a sequential numeric index. This means the
index of nested table variables is densely populated. You should use a nested table when you
don’t know the number of items that will go in the collection before declaring the variable. Like
lists in other programming languages, the nested table can grow in size after it is declared.
Syntax:
[OR]
SET SERVEROUTPUT ON
DECLARE
TYPE list_nt_type IS TABLE OF NUMBER; --creating composite data type
list_nt_t list_nt_type := list_nt_type();
BEGIN
FOR i IN 1..100
LOOP
list_nt_t.EXTEND;
list_nt_t(i) := i;
DBMS_OUTPUT.PUT_LINE('Value in Slot Number: '||i||' is: '||list_nt_t(i));
END LOOP;
END;
/
Predefined exceptions.
User defined exceptions.
Pragma exception.
Raise application errors.
Oracle handles few exceptions on its own such exceptions are called predefined
exceptions or oracle defined exceptions. There are various predefined exceptions and
below are few very important ones.
SET SERVEROUTPUT ON
DECLARE
Lv_salaryEmployees.employee_id%TYPE;
Lv_commEmployees.salary%TYPE;
Lv_tot_salEmployees.salary%TYPE;
BEGIN
SELECT salary, commission_pct
INTO Lv_salary, Lv_comm
FROM Employees
WHERE employee_id = &employee_id;
SET SERVEROUTPUT ON
DECLARE
Lv_salaryEmployees.employee_id%TYPE;
Lv_commEmployees.salary%TYPE;
Lv_tot_salEmployees.salary%TYPE;
BEGIN
SELECT salary, commission_pct
INTO Lv_salary, Lv_comm
FROM Employees
WHERE department_id = &department_id;
SET SERVEROUTPUT ON
DECLARE
Lv_salaryEmployees.employee_id%TYPE;
Lv_commEmployees.salary%TYPE;
Lv_quotEmployees.salary%TYPE;
BEGIN
SELECT salary, commission_pct
INTO Lv_salary, Lv_comm
FROM Employees
WHERE employee_id = &employee_id;
Lv_comm := NVL(Lv_comm,0);
Lv_quot := Lv_salary/Lv_comm;
DBMS_OUTPUT.PUT_LINE('Employee total salary is: '||Lv_quot);
EXCEPTION
WHEN ZERO_DIVIDE
THEN
DBMS_OUTPUT.PUT_LINE('Wrong value is used to find quotient, use non zero value');
END;
/
SET SERVEROUTPUT ON
DECLARE
Lv_department_idDepartments.department_id%TYPE := &id;
Lv_department_nameDepartments.department_name%TYPE :=&name;
Lv_locationDepartments.location_id%TYPE:=&location;
Lv_managerDepartments.manager_id%TYPE:=&manager;
BEGIN
INSERT INTO departments (department_id, department_name, location_id, manager_id)
VALUES (Lv_department_id, Lv_department_name, Lv_location, Lv_manager);
COMMIT;
EXCEPTION
WHEN DUP_VAL_ON_INDEX
THEN
DBMS_OUTPUT.PUT_LINE('Trying to create new department with already existing id');
END;
/
SET SERVEROUTPUT ON
DECLARE
Lv_emp_nameEmployees.first_name%TYPE;
Lv_salaryEmployees.salary%TYPE;
Lv_commEmployees.commission_pct%TYPE;
Lv_tot_salEmployees.salary%TYPE;
CURSOR cur_emp IS
SELECT first_name, salary, commission_pct
FROM Employees
WHERE department_id = &department_id;
BEGIN
OPEN cur_emp;
LOOP
--OPEN cur_emp;
FETCH cur_emp INTO Lv_emp_name, Lv_salary, Lv_comm;
EXIT WHEN cur_emp%NOTFOUND;
Lv_tot_sal := Lv_salary + NVL(Lv_comm, 0)*Lv_salary;
DBMS_OUTPUT.PUT_LINE('Emp Name: '||Lv_emp_name||' and Total Salary: '||Lv_tot_sal);
--CLOSE cur_emp;
END LOOP;
CLOSE cur_emp;
--CLOSE cur_emp;
INSERT INTO departments (department_id, department_name, location_id, manager_id)
VALUES (&Lv_department_id, &Lv_department_name, &Lv_location, &Lv_manager);
COMMIT;
EXCEPTION
WHEN INVALID_CURSOR
THEN
DBMS_OUTPUT.PUT_LINE('Invalid cursor operation');
WHEN CURSOR_ALREADY_OPEN
User defined exceptions are exceptions defined by the user to trap exceptional explicitly.
These exceptions do not raise by Oracle and user should pay attention to raise these kind
of exceptions. User defined exceptions are basically used to trap the application level
exceptions based on requirements.
SET SERVEROUTPUT ON
DECLARE
Lv_new_salEmployees.salary%TYPE;
Le_invalid_empException;
Le_max_thr_crossed Exception;
BEGIN
UPDATE Employees SET salary = salary+(10/100)*salary
WHERE employee_id = &employee_id RETURN salary INTO Lv_new_sal;
IF SQL%NOTFOUND
THEN
RAISE Le_invalid_emp;
END IF;
IF Lv_new_sal> 25000
THEN
RAISE Le_max_thr_crossed;
END IF;
DBMS_OUTPUT.PUT_LINE('Employee new salary is: '||Lv_new_sal);
EXCEPTION
WHEN Le_invalid_emp
THEN
DBMS_OUTPUT.PUT_LINE('Employee not found');
WHEN Le_max_thr_crossed
THEN
DBMS_OUTPUT.PUT_LINE('Employee crossed max threshold salary');
WHEN OTHERS
THEN
DBMS_OUTPUT.PUT_LINE('Salary update failed due to, '||SQLCODE);
END;
/
Non predefined exceptions are similar to predefined exceptions; however, they are not
defined as predefined PL/SQL exceptions in Oracle server. They are standard Oracle errors.
Pragma exceptions are used to create and trap exceptions for non-predefined oracle errors
SET SERVEROUTPUT ON
DECLARE
Le_insert_null Exception;
PRAGMA EXCEPTION_INIT(Le_insert_null, -1400);
BEGIN
INSERT INTO departments (department_id, department_name) VALUES (285, NULL);
--COMMIT;
EXCEPTION
WHEN Le_insert_null
THEN
DBMS_OUTPUT.PUT_LINE('Null values are not allowed for specified column');
WHEN OTHERS
1.4.
THEN R
a
DBMS_OUTPUT.PUT_LINE('Failed due to : '||SQLCODE);
END; i
/
s
e Application Errors:
SET SERVEROUTPUT ON
DECLARE
Lv_new_SalEmployees.salary%TYPE;
Le_max_thr_crossed Exception;
BEGIN
UPDATE employees SET salary = salary+(10/100)*salary WHERE employee_id = &employee_id
RETURN salary INTO Lv_new_Sal;
IF SQL%NOTFOUND
THEN
RAISE_APPLICATION_ERROR(-20001,'Invalid employee Id is used');
END IF;
IF Lv_new_sal> 25000
THEN
RAISE Le_max_thr_crossed;
END IF;
--COMMIT;
EXCEPTION
2. Procedures:
A procedure contains a group of SQL and PL/SQL statements. Procedures allow you to centralize
your business logic in the database and may be used by any program that accesses the
database.
Procedure is created using "CREATE PROCEDURE" Statement. The simplified syntax for
the CREATE PROCEDURE statement is as follows,
Where,
OR REPLACE means the procedure is to replace an existing procedure.
Procedure_name is the name of the procedure.
Parameter_name is the name of a parameter that is passed to the procedure.
You maypass multiple parameters to a procedure.
IN | OUT | IN OUT is the mode of the parameter. You may pick one of the
following
modes for each parameter:
IN, which is the default mode for a parameter. An IN parameter must be set to a
value when the procedure is run. The value of an IN parameter cannot be
changedin the procedure body.
OUT, which means the parameter is set to a value in the procedure body.
IN OUT, which means the parameter can have a value when the procedure is
run,and the value can be changed in the body.
Type is the type of the parameter.
Procedure body contains the actual code for the procedure.
USER_PROCEDURES is the Meta data that gives information about the procedures.
Procedures can be identified based on OBJECT_TYPE column in USER_PROCEDURES.
SELECT * FROM user_procedres WHERE object_type = 'PROCEDURE';
[OR]
SELECT * FROM user_objects WHERE object_type = 'PROCEDURE';
After compiling procedure, below command can be used to list the compilation errors of
procedure, if any.
SQL> SHOW ERRORS;
Create a stored procedure to get employee name and Manager Information as output
parameters.
Output:
3. Functions:
A function is similar to a procedure, except that a function must return a value.
Together, stored procedures and functions are sometimes referred to as stored subprograms
because they are small programs.
Create a function.
Call a function.
Get information on functions.
Drop a function.
Where
OR REPLACE means the function is to replace an existing function.
Function_name is the name of the function.
Parameter_name is the name of a parameter that is passed to the
function. Multiple parameters can be passed to a function.
IN |OUT | IN OUT is the mode of the parameter.
type is the type of the parameter.
Function_body contains actual code for the function. Unlike a procedure,
the body of a function must return a value of the type specified in the
RETURN clause.
GET_EMP_TOT_SAL(1750)
---------------------
0
Here Employee number is 1750 which does not exists in table and hence total salary returned is 0.
Create a function to check whether employee is available and return total salary of employee
if available else notify as subscriber is not found.
RETURN BOOLEAN
AS
Lv_salary employees.salary%TYPE;
Lv_comm employees.commission_pct%TYPE;
BEGIN
SELECT salary, commission_pct INTO Lv_salary, Lv_comm
FROM employees WHERE employee_id = i_emp_id;
o_tot_sal := Lv_salary + NVL(lv_comm, 0)*Lv_salary;
RETURN TRUE;
EXCEPTION
WHEN OTHERS THEN
RETURN FALSE;
END Get_check_emp_tot_sal;
/
A function can be called from SQL* plus session as other built-in functions do (but it
depends on the logic written in the function body).
user defined functions information can be retrieved from data dictionary table called
USER_PROCEDURES where OBJECT_TYPE is "FUNCTION".
[OR]
User defined functions can be dropped using a command called "DROP FUNCTION". Below is an
example.
4. Packages:
In this section, you’ll learn how to group procedures and functions together into
packages. Packages allow you to encapsulate related functionality into one self-contained unit.
By modularizing your PL/SQL code through the use of packages, you can build up your own
libraries of code that other programmers can reuse.
Packages are typically made up of two components: a specification and a body. The
package specification lists the available procedures, functions, types, and objects. You can make
the items listed in the specification available to all database users, and these items as being
referred as public (although only users you have granted privileges to access your package can
use it). The specification doesn’t contain the code that makes up the procedures and functions;
the code is contained in the package body.
Any items in the body that are not listed in the specification are private to the package.
Private items can be used only inside the package body. By using a combination of public and
private items, you can build up a package whose complexity is hidden from the outside world.
This is one of the primary goals of all programming: hide complexity from your users.
You create a package specification using the CREATE PACKAGE statement. The simplified
syntax for the CREATE PACKAGE statement is as follows:
Where
OR REPLACE means the package specification is to replace an existing
package specification.
Package_name is the name of the package.
package_specification lists the public procedures, functions, types, and
objects available to your package’s users.
Below is the package specification which contains TYPE for ref cursor, Function to get all
employee records and procedure to update employee salary. All these objects stored in
combine in a single unit called package.
A package body can be created using "CREATE PACKAGE BODY" statement. The
simplified syntax for the CREATE PACKAGE BODY statement is as follows:
Where
Package_name is the name of the package, which must match the
package name in the specification.
Package_body contains the code for the procedures and functions.
The update_emp_salary() procedure updates salary with new hike percentage and
COMMITs transaction. This procedure is identical to the one shown earlier in the section
“Creating a Procedure".
When calling functions and procedures in a package, you must include the package name in the
call. The following example calls " Emplployee_utility_pkg.get_emp_ref_cursor(), which returns
a reference to the cursor containing information of employee_id, first_name and salary.
SQL> SELECT employee_id, first_name, salary FROM employees WHERE employee_id = 100;
Now, employee (employee_id = 100, Steven) salary increased to 30000 (24000 + 25% hike
added). update of employee information is done via procedure created in package.
You can get information on your functions and procedures in a package from the
user_procedures view; this view was covered earlier in the section “Getting Information
on Procedures.” The following example retrieves the object_name and procedure_name
columns from user_procedures :
Package can be dropped by using "DROP PACKAGE " command. For e.g., the following
statement drops " EMPLPLOYEE_UTILITY_PKG".
5. Triggers:
A trigger is a procedure that is run (or fired ) automatically by the database when a specified
DML statement (INSERT, UPDATE, or DELETE) is run against a certain database table. Triggers
are useful for doing things like advanced auditing of changes made to column values in a table.
A trigger may fire before or after a DML statement runs. Also, because a DML statement can
affect more than one row, the code for the trigger may be run once for every row affected (a
row-level trigger), or just once for all the rows (a statement-level trigger). For example, if you
create a row level trigger that fires for an UPDATE on a table, and you run an UPDATE statement
that modified ten rows of that table, then that trigger would run ten times. If, however, your
trigger was a statement-level trigger, the trigger would fire once for the whole UPDATE
statement, regardless of the number of rows affected.
There is another difference between a row-level trigger and a statement-level trigger: A row
level trigger has access to the old and new column values when the trigger fires as a result of an
UPDATE statement on that column. The firing of a row-level trigger may also be limited using a
trigger condition; for example, you could set a condition that limits the trigger to fire only when
a column value is less than a specified value.
As mentioned, triggers are useful for doing advanced auditing of changes made to column
values. In the next section, you’ll see a trigger that records when a employee's salary is
updated; when this occurs, the trigger will add a row to the employee_salary_audit table.
The employee_salary_audit table is created by the following statement
As you can see, the employee_id column of the employee_salary_audit table is a foreign key to
the employee_id column of the employees table. The old_salary column will be used to store
the old salary of a employee prior to the change, and the new_salary column will be used to
store the new salary after the change.
You create a trigger using the CREATE TRIGGER statement. The simplified syntax for the
CREATE TRIGGER statement is as follows:
Where
OR REPLACE means the trigger is to replace an existing trigger, if present.
trigger_name is the name of the trigger.
BEFORE means the trigger fires before the triggering event is performed. AFTER means the
trigger fires after the triggering event is performed. INSTEAD OF means the trigger fires instead
of performing the triggering event. FOR, which is new for Oracle Database 11g, allows you to
create a compound trigger consisting of up to four sections in the trigger body.
trigger_event is the event that causes the trigger to fire.
table_name is the table that the trigger references.
FOR EACH ROW means the trigger is a row-level trigger, that is, the code contained within
trigger_body is run for each row when the trigger fires. If you omit FOR EACH ROW, the trigger is
a statement-level trigger, which means the code within trigger_body is run once when the
trigger fires.
{ENABLE | DISABLE} is new for Oracle Database 11g and indicates whether the trigger is initially
enabled or disabled when it is created (the default is ENABLE). You enable a disabled trigger by
using the ALTER TRIGGER trigger_name ENABLE statement or by enabling all triggers for a table
using ALTER TABLE table_name ENABLE ALL TRIGGERS.
trigger_condition is a Boolean condition that limits when a trigger actually runs its code.
trigger_body contains the code for the trigger.
The example trigger you’ll see in this section fires before an update of the salary column in the
employees table; therefore, I’ll name the trigger before_emp_sal_update. Also, because I
want to use the salary column values before and after an UPDATE statement modifies the salary
column’s value, I must use a row-level trigger.
STEP3: Write trigger to track salary changes in a audit table created above.
STEP4: Update salary of employees for department 100. Increase salary by 10%.
SQL> UPDATE employees SET salary = salary + (salary*0.10) WHERE department_id = 100;
6 rows updated.
SQL> COMMIT;
Committed
Write a trigger to track the table changes with user name, time and type of operation.
STEP 1: Create Emp_Chg_Track_Tab
SQL> CREATE TABLE Emp_Chg_Track_Tab
(operation VARCHAR2(6),
User_name VARCHAR2(6),
date_of_operation DATE);
3 rows updated.
committed.
OPERATION USER_NAME DATE_OF_OPERATION
--------- --------- -----------------
UPDATE HR 12-APR-15
USER_TRIGGERS meta data or data dictionary gives the information about triggers
available in that particular user.
USER_OBJECTS meta data or data dictionary with OBJECT_TYPE as TRIGGER also gives
same info mentioned above.
--Disable trigger.
--Enable trigger.
By Enabling trigger, it can be fired automatically when specified DML is executed. You
can test and verify the firing of trigger.
A Trigger can be dropped by using DROP TRIGGER command. Below is the sample
command to drop trigger.