Oracle Tutorials: PL/SQL
Oracle Tutorials
PL/SQL
Procedural Language / Structured Query Language
Zbigniew Baranowski
Agenda
Overview of PL/SQL
Blocks
Variables and placeholders
Program Flow Control Statements
Cursors
Functions and Procedures
Error Handling
Packages
Triggers
Jobs
Oracle Tutorials: PL/SQL
1 June 2006 2
PL/SQL
Procedural language extension to SQL
procedural data manipulation
conditionals, loops etc.
High-level language features
Complex data types
Data encapsulation
Modular programming
Integrated with the ORACLE database server
Server-side
parsing / compilation
execution / interpretation
End-user platform independent (like SQL)
Oracle Tutorials: PL/SQL
1 June 2006 3
Writing PL/SQL programs
Each program is a block consisting of
PL/SQL statements – logic
SQL statements – data manipulation
Type of block
Anonymous
External scripts (file or input)
Nested blocks
Named / Stored (on the database)
Oracle Tutorials: PL/SQL
1 June 2006 4
PL/SQL execution
Oracle Tutorials: PL/SQL
1 June 2006 5
PL/SQL Block Structure
DECLARE –-declaration section (types, variables, …)
l_commission NUMBER;
L_COMM_MISSING EXCEPTION;
BEGIN –-executable section (program body)
SELECT commission_pct / 100 INTO l_commission
FROM employees WHERE employee_id = emp_id;
IF l_commission IS NULL THEN RAISE COMM_MISSING;
ELSE UPDATE employees
SET salary = salary + bonus*l_commission
WHERE employee_id = emp_id;
END IF;
EXCEPTION --exception section (error handling)
WHEN L_COMM_MISSING THEN DBMS_OUTPUT.PUT_LINE('This
employee does not receive a commission.');
END;
Oracle Tutorials: PL/SQL
1 June 2006 6
PL/SQL placeholders
All SQL types are supported by PL/SQL
Numerical types
NUMBER, PLS_INTEGER
Many derived types, e.g. POSITIVE
Character types
CHAR, VARCHAR2, NCHAR,…
Other scalar types
BOOLEAN, DATE, UROWID, RAW
Oracle Tutorials: PL/SQL
1 June 2006 7
PL/SQL placeholders
Scalar type
variable
constant
Composite/vector type
record
used for reading rows from table
Collections
Associative Array - dictionary
Variable-sized Array (VARRAY) – fixed size
Nested Tables – dynamic size
Oracle Tutorials: PL/SQL
1 June 2006 8
PL/SQL placeholders
Scalar type
variable
constant
DECLARE
l_x NUMBER := 20000;
l_message VARCHAR2(40);
C_PI CONSTANT NUMBER(3,2):=3.14;
BEGIN
l_x := 1000 * C_PI;
l_message := 'Hello world';
END;
Oracle Tutorials: PL/SQL
1 June 2006 9
PL/SQL placeholders
Scalar type
variable
constant
Single composite/vector type
record
used for reading rows from table
Collections
TYPE T_TIME IS RECORD (minutes INTEGER, hours NUMBER(2));
current_time_rec T_TIME;
Associative Array
Current_time_rec.hours := 12;
Variable-sized Array (VARRAY)
Nested Tables
Oracle Tutorials: PL/SQL
1 June 2006 10
PL/SQL placeholders
Scalar type
DECLARE
variable
TYPE T_POPULATION IS TABLE OF NUMBER INDEX BY VARCHAR2(64);
constant
l_city_population T_POPULATION;
l_i number;
BEGIN
Single composite/vector type := 2000;
l_city_population('Smallville')
l_i:= l_city_population('Smallville') ;
record
END;
used for reading rows from table
/
Collections
Associative Array
Variable-sized Array (VARRAY)
Nested Tables
Oracle Tutorials: PL/SQL
1 June 2006 11
PL/SQL placeholders
DECLAREScalar type
TYPE T_FOURSOME IS VARRAY(4) OF VARCHAR2(15);
variable
l_team T_FOURSOME := T_FOURSOME('John', 'Mary', 'Alberto');
BEGIN constant
l_team.EXTEND; -- Append one null element
l_team(4):='Mike'; -- Set 5th element element
Single composite/vector type
DBMS_OUTPUT.PUT_LINE( l_team( l_team.first ) ); -- Print first element
DBMS_OUTPUT.PUT_LINE( l_team( l_team.last ) ); -- Print last element
record
END; used for reading rows from table
/
Collections
Associative Array
Variable-sized Array (VARRAY)
Nested Tables
Oracle Tutorials: PL/SQL
1 June 2006 12
PL/SQL placeholders
Scalar type
DECLARE
variable
TYPE T_ROSTER IS TABLE OF VARCHAR2(15);
l_names T_ROSTER := T_ROSTER('D Caruso', 'J Hamil', 'D Piro', 'R Singh');
constant
l_i number;
BEGIN
FOR l_i IN l_names.FIRST .. L_names.LAST LOOP --For first to last element
Single composite/vector type
DBMS_OUTPUT.PUT_LINE(l_names(l_i));
END LOOP;
record
END;
used for reading rows from table
/
Collections
Associative Array
Variable-sized Array (VARRAY)
Nested Tables
Oracle Tutorials: PL/SQL
1 June 2006 13
Attributes %TYPE & %ROWTYPE
%TYPE references type of a variable or a database
column
%ROWTYPE references type of a record structure,
table row or a cursor
Advantages:
Actual type does not need to be known
referenced type had changed -> will be recompiled
automatically
Oracle Tutorials: PL/SQL
1 June 2006 14
%TYPE & %ROWTYPE Examples
variable declarations
balance NUMBER(7,2);
minimum_balance balance%TYPE := 10.00;
my_dname scott.dept.dname%TYPE;
dept_rec dept%ROWTYPE;
SELECT deptno, dname, loc INTO dept_rec
FROM dept WHERE deptno = 30;
using record variable to read a row from a table
Oracle Tutorials: PL/SQL
1 June 2006 15
PL/SQL Control Structures
Conditional Control
Using IF and CASE statements
DECLARE
DECLARE := 20000;
l_sales NUMBER(8,2)
l_grade CHAR(1) := 'B';
l_bonus NUMBER(6,2);
BEGIN BEGIN
CASETHEN
IF l_sales > 50000 l_grade
l_bonus := 1500;
WHEN l_bonus
ELSIF l_sales > 35000 THEN 'A' THEN
:= 500;
DBMS_OUTPUT.PUT_LINE('Excellent');
ELSE l_bonus := 100;
END IF; WHEN 'B' THEN DBMS_OUTPUT.PUT_LINE('Very
Good');
UPDATE employees SET salary = salary + l_bonus;
WHEN 'C' THEN DBMS_OUTPUT.PUT_LINE('Good');
END;
WHEN 'D' THEN DBMS_OUTPUT.PUT_LINE('Fair');
WHEN 'F' THEN DBMS_OUTPUT.PUT_LINE('Poor');
ELSE DBMS_OUTPUT.PUT_LINE('No such grade');
Sequential Control END CASE;
END;
Using GOTO statement
Oracle Tutorials: PL/SQL
1 June 2006 16
PL/SQL Control Structures
Iterative loops DECLARE
l_i NUMBER := 0;
Simple loop (infinite) BEGIN
LOOP
WHILE loop DBMS_OUTPUT.PUT_LINE (TO_CHAR(l_i));
l_i:=l_i+1;
FOR loop END LOOP;
Numeric range WHILE l_i < 10 LOOP
Reversed DBMS_OUTPUT.PUT_LINE (TO_CHAR(l_i));
l_i := l_i + 1;
Cursor based END LOOP;
FOR l_i IN 1..500 LOOP
DBMS_OUTPUT.PUT_LINE (TO_CHAR(l_i));
END LOOP;
FOR l_i IN REVERSE 1..3 LOOP
DBMS_OUTPUT.PUT_LINE (TO_CHAR(l_i));
END LOOP;
END;
1 June 2006
Oracle Tutorials: PL/SQL 17
PL/SQL Control Structures
Iterative loops DECLARE
l_i NUMBER := 0;
Named loops l_j NUMBER := 0;
l_s NUMBER :=0;
BEGIN
<<outer_loop>>
Exiting loops LOOP
l_i := l_i + 1;
EXIT statement <<inner_loop>>
LOOP
Loop skipping l_j := l_j + 1;
l_s := l_s + l_i * l_j;
CONTINUE EXIT inner_loop WHEN (l_j >
5);
EXIT outer_loop WHEN ((l_i
* l_j) > 15);
END LOOP inner_loop;
DBMS_OUTPUT.PUT_LINE('Sum:'||
TO_CHAR(l_s));
IF l_s > 100 THEN EXIT;
END IF;
Oracle Tutorials:
END LOOPPL/SQL
outer_loop;
1 June 2006 END; 18
Accessing Data in the Database
Selecting at most one row:
SELECT INTO statement
SELECT COUNT(*) INTO variable FROM table;
SELECT * INTO record FROM table WHERE …;
Selecting Multiple rows:
Cursors
Inserting and updating
INSERT INTO table VALUES (var1, var2, …);
Oracle Tutorials: PL/SQL
1 June 2006 19
Cursors
Every SQL query produces a result set - cursor
set of rows that answer the query
resides on the server in the client process memory
PL/SQL program can read the result set in interating
fashon EMP_NO EMP_NAME EMP_JOB EMP_HIREDATE EMP_DEPTNO
380 KING CLERK 1-JAN-1982 10
select 381 BLAKE ANALYST 11-JAN-1982 30
emp_no 392 CLARK CLERK 1-FEB-1981 30
,emp_name Result Set
569 SMITH CLERK 2-DEC-1980 20
,emp_job 566 JONES MANAGER 5-JUL-1978 30
from employees 788 SCOTT ANALYST 20-JUL-1981 10
where emp_no > 500; 876 ADAMS CLERK 14-MAR-1980 10
902 FORD ANALYST 25-SEP-1978 20
1 June 2006
Oracle Tutorials: PL/SQL 20
Defining explicit cursors
The simplest cursor:
CURSOR my_cursor IS SELECT * from table;
Full cursor syntax
CURSOR name(parameter_list) RETURN rowtype IS SELECT …;
The SQL select statement is static (hardcoded)
But may be parameterized
The return type clause is useful in packages
Attributes
%FOUND, %NOTFOUND, %ROWCOUNT, %ISOPEN
Oracle Tutorials: PL/SQL
1 June 2006 21
Using explicit cursors
Fetching results of a query into RECORD
DECLARE
l_employees employees%ROWTYPE;
CURSOR l_c (p_low NUMBER DEFAULT 0, p_high NUMBER DEFAULT 99) is
SELECT * FROM employees WHERE job_id > p_low AND job_id < p_high;
BEGIN
OPEN l_c(3,20);
LOOP
FETCH l_c INTO l_employees;
EXIT WHEN l_c%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(l_employees.last_name || l_employees.job_id );
END LOOP;
CLOSE l_c;
END;
Oracle Tutorials: PL/SQL
1 June 2006 22
Implicit cursor
DECLARE
l_rows number(5);
BEGIN
UPDATE employee SET salary = salary + 1000;
IF SQL%NOTFOUND THEN
dbms_output.put_line('None of the salaries where updated');
ELSIF SQL%FOUND THEN l_rows := SQL%ROWCOUNT;
dbms_output.put_line('Salaries for ' || l_rows || 'employees are
updated');
END IF;
END;
Oracle Tutorials: PL/SQL
1 June 2006 23
Dynamic PL/SQL
Execution of statement composed in strings
For SQL which text is unknown at compiling time
Some parts of SQL cannot be bind by variables
table name
database link
…
Be aware of SQL injections!
Use dynamic SQL when it is really needed
Oracle Tutorials: PL/SQL
1 June 2006 24
Dynamic SQL & PL/SQL
Inserting
sql_stmt := 'INSERT INTO payroll VALUES (:x, :x, :y, :x)';
EXECUTE IMMEDIATE sql_stmt USING a, b; -- using variables
Selecting data from dynamic table_name
EXECUTE IMMEDIATE 'select id form '||table_name||' where name=:a '
using job_name returning into job_id;
Dynamic PL/SQL
plsql_block := 'BEGIN calc_stats(:x, :x, :y, :x); END;';
EXECUTE IMMEDIATE plsql_block USING a, b;
Oracle Tutorials: PL/SQL
1 June 2006 25
PL/SQL Subprograms
Named block
stored in the database
can have set of parameters
invocation
from named block
from anonymous blocks
recursively
Subprogram types
Procedures
complex data processing
Functions
frequent, simple operations
returns a value
Oracle Tutorials: PL/SQL
1 June 2006 26
PL/SQL Subprograms
The header specifies:
Name and parameter list
Return type (function headers)
Parameters:
Any of them can have a default value
Parameter input modes:
IN (default)
Passes value to that cannot be changed by the subprogram
OUT
Return value. Should be initialized in the subprogram
IN OUT
Passes a value and returns updated one by subprogram
Oracle Tutorials: PL/SQL
1 June 2006 27
PL/SQL Procedures
Procedure definition
CREATE OR REPLACE PROCEDURE EXE$RAISE_SALARY (p_emp_id IN NUMBER
, p_amount IN NUMBER) IS
BEGIN
UPDATE employees SET salary = salary + p_amount
WHERE employee_id = p_emp_id;
END EXE$RAISE_SALARY;
Procedure invocation
EXE$RAISE_SALARY(emp_num, bonus);
EXE$RAISE_SALARY(l_amount => bonus, l_emp_id => emp_num);
EXE$RAISE_SALARY(emp_num, l_amount => bonus);
Oracle Tutorials: PL/SQL
1 June 2006 28
PL/SQL Functions
Function definition
CREATE OR REPLACE FUNCTION STF$HALF_OF_SQUARE (p_original NUMBER)
RETURN NUMBER IS
BEGIN
RETURN (p_original * p_original)/2 + (p_original * 4);
END STF$HALF_OF_SQUARE;
Function invocation
square INTEGER := STF$HALF_OF_SQUARE(25);
select STF$HALF_OF_SQUARE( a ) from squers;
Oracle Tutorials: PL/SQL
1 June 2006 29
Subprograms privileges
Creator/owner has full privileges on stored objects
Invoker that is not an owner has to have EXECUTE
privilege granted
-- USER1
create or replace function my_fuction1 is…
grant execute on my_procedure1 to user2;
-- USER2
execute user1.myprocedure;
Granted privs can be checked in USER_TAB_PRIVS
Oracle Tutorials: PL/SQL
1 June 2006 30
Subprograms rights
Definer rights (default for named blocks)
create or replace procedure procedure_name [authid definer]
is…
Invoker rights
create or replace function procedure_name authid current_user
is…
Anonymous blocks have always invoker rights!
Oracle Tutorials: PL/SQL
1 June 2006 31
Error Handling
An error interrupts the execution of the program
An exception is raised
Exception to be handled
in the exception section or
will be propagated to the enclosing block
After the exception is handled, the control passes to
the enclosing block
Oracle Tutorials: PL/SQL
1 June 2006 32
PL/SQL Exceptions
The programmer can create, name and raise
exception
Exceptions can by caught and handled by the user’s
code
Exceptions does not rollback or commit changes!
Categories
Internally defined (without name, just error code)
Predefined (with name and error code)
User-defined (with name, raised always explicitly)
Oracle Tutorials: PL/SQL
1 June 2006 33
PL/SQL Exceptions
DECLARE
l_out_of_stock EXCEPTION;
l_number_on_hand NUMBER := 0;
BEGIN
IF l_number_on_hand < 1 THEN
RAISE l_out_of_stock;
END IF;
EXCEPTION
WHEN l_out_of_stock THEN
DBMS_OUTPUT.PUT_LINE ( 'Encountered out of stock error' );
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE ( 'Houston we''ve got a problem!' );
END;
END; Oracle Tutorials: PL/SQL
1 June 2006 34
Packages
Group logically related PL/SQL types, items and
modules
2 parts:
Specification public interface
Body private implementation
Packages are global
Cannot be called, parameterized, or nested.
Package state persist for the duration of the database
session
Oracle Tutorials: PL/SQL
1 June 2006 35
Why use Packages
Modularity
Encapsulation of data and functionality
Clear specifications independent of the
implementation
Easier development
Added functionality:
global variables
global types
Better performance
Oracle Tutorials: PL/SQL
1 June 2006 36
Package Specification
Header
Declarations of global types and variables
Specification of cursors
With RETURN clause, but no SELECT statement
Specification of public modules
Oracle Tutorials: PL/SQL
1 June 2006 37
Package Specification
CREATE OR REPLACE PACKAGE KNL_EMP_ADM AS
TYPE T_EMPRECTYP IS RECORD (emp_id NUMBER, sal NUMBER);
CURSOR desc_salary RETURN T_EMPRECTYP ;
invalid_salary EXCEPTION;
PROCEDURE EXE$FIRE_EMPLOYEE (p_emp_id NUMBER);
PROCEDURE EXE$RAISE_SALARY (p_emp_id NUMBER,p_amount NUMBER);
FUNCTION STF$HIGHEST_SALARY (p_n NUMBER) RETURN T_EMPRECTYP;
END KNL_EMP_ADM;
Oracle Tutorials: PL/SQL
1 June 2006 38
Package Body
Header
Additional declarations of types and variables
Specification and SELECT statements of cursors
Specification and body of modules
Initialization code
Execution and exception sections
Executed once when the package is first accessed
Oracle Tutorials: PL/SQL
1 June 2006 39
Package Body
CREATE OR REPLACE PACKAGE BODY KNL_EMP_ADM AS
number_hired NUMBER;
CURSOR desc_salary RETURN T_EMPRECTYP IS
SELECT employee_id, salary FROM employees ORDER BY salary
DESC;
PROCEDURE EXE$FIRE_EMPLOYEE (p_emp_id NUMBER) IS
BEGIN
DELETE FROM employees WHERE employee_id = p_emp_id;
END EXE$FIRE_EMPLOYEE;
PROCEDURE EXE$RAISE_SALARY (p_emp_id NUMBER,p_amount NUMBER) IS
...
BEGIN
INSERT INTO emp_audit VALUES (SYSDATE, USER, 'EMP_ADMIN');
number_hired := 0;
END;
END KNL_EMP_ADM; Oracle Tutorials: PL/SQL
1 June 2006 40
Oracle Supplied Packages
Extend the functionality of the database
Some example packages:
DBMS_JOB: for task scheduling
DBMS_PIPE: for communication between sessions
DBMS_OUTPUT: display messages to the session output
device
UTL_HTTP: makes HTTP callouts.
Many others…
Oracle Tutorials: PL/SQL
1 June 2006 41
Triggers
Stored procedure
Execute automatically when:
data modification (DML Trigger)
INSERT, UPDATE, UPDATE column or DELETE
schema modification (DDL Trigger)
system event, user logon/logoff (System Trigger)
Basic DML triggers types:
BEFORE statement
BEFORE each row modification
AFTER each row modification
AFTER statement
INSTEAD OF - to enable data modification by views
Oracle Tutorials: PL/SQL
1 June 2006 42
When To Use Triggers
Automatic data generation
Auditing (logging), statistics
Derived data
Data replication
Special referential constrains
Complex logic
Distributed constrains
Time based constrains
Updates of complex views
Triggers may introduce hard to spot
interdependencies to the database schema
Oracle Tutorials: PL/SQL
1 June 2006 43
Trigger Body
Built like a PL/SQL procedure
Additionally:
Type of the triggering event can be determined inside
the trigger using conditional predicators
IF inserting THEN … END IF;
Old and new row values are accessible via :old
and :new qualifiers (record type variables)
Oracle Tutorials: PL/SQL
1 June 2006 44
Trigger Example
CREATE OR REPLACE TRIGGER audit_sal
BEFORE UPDATE OF salary ON employees
FOR EACH ROW
BEGIN
INSERT INTO emp_audit
VALUES( :old.employee_id, SYSDATE, :new.salary, :old.salary );
COMMIT;
END;
Oracle Tutorials: PL/SQL
1 June 2006 45
Jobs
Job
Schedule
PL/SQL subprogram (but not only)
Many possibilities for the scheduling
Creation
Using DBMS_SCHEDULER internal package
Alternative DBMS_JOB is old and should by avoided
Privileges needed
execute on DBMS_SCHEDULER
create job
Oracle Tutorials: PL/SQL
1 June 2006 46
Jobs example
Daily execution (everyday at 12) of
my_saved_procedure
BEGIN
DBMS_SCHEDULER.CREATE_JOB (
job_name => 'my_new_job1',
program_name => 'my_saved_procedure',
repeat_interval => 'FREQ=DAILY;BYHOUR=12',
comments => 'Daily at noon');
END;
/
Oracle Tutorials: PL/SQL
1 June 2006 47
Advantages of PL/SQL
Tightly integrated with SQL
Reduced network traffic
Portability - easy deployment and distribution
Data layer separated from client language
Modification without changing of application code
Can be shared by many platform
Server-side periodical data maintenance (jobs)
Oracle Tutorials: PL/SQL
1 June 2006 48