PL/SQL - Oracle's Procedural Language Extension To SQL
PL/SQL - Oracle's Procedural Language Extension To SQL
ISAD211 1
PL/SQL - Oracle's Procedural
Language extension to SQL
loosely based on Ada
includes (inter alia)
block structure
datatypes (including Boolean)
variables & constants
assignment statement
conditional statements
if .. then
if .. then .. else
if .. then .. elsif
loops
basic loop (needs exit condition)
for loop
while loop
ISAD211 3
Anonymous block examples
BEGIN
DBMS_OUTPUT.PUT_LINE('Hello World!');
END;
DECLARE
v_day_of_week VARCHAR2(12); -- local variable
BEGIN
SELECT TO_CHAR(SYSDATE, 'Day')
INTO v_day_of_week
FROM sys.dual;
IF v_day_of_week IN ('Saturday', 'Sunday')
THEN
-- note use of extra quote in string
DBMS_OUTPUT.PUT_LINE('It''s the weekend!');
ELSE
DBMS_OUTPUT.PUT_LINE('Too bad - it''ll be the weekend
soon');
END IF;
END; SET SERVEROUTPUT ON
to get output from
ISAD211 DBMS_OUTPUT.PUT_LINE 4
Stored programs
Codestored in the database and
executed on the server
advantages of DB approach
storeonce, use many
backup/recovery
access control
Multiple
use by multiple
users/applications
GRANT EXECUTE ON <proc_name> TO <username>
ISAD211 5
Stored procedure
CREATE OR REPLACE PROCEDURE TGITW IS
v_day_of_week VARCHAR2(12); -- DECLARE not used here
BEGIN
SELECT TO_CHAR(SYSDATE, 'Day')
INTO v_day_of_week
FROM sys.dual;
IF v_day_of_week IN ('Saturday', 'Sunday') THEN
DBMS_OUTPUT.PUT_LINE('It''s the weekend!');
ELSE
DBMS_OUTPUT.PUT_LINE('Too bad - it''ll be the weekend soon');
END IF;
END;
-- SQL*Plus
exec TGITW
ISAD211 6
Stored function
CREATE OR REPLACE FUNCTION get_age
(p_birth_date IN DATE) -- INput parameter
RETURN INTEGER IS -- data type of result
v_age INTEGER;
BEGIN
SELECT TRUNC(MONTHS_BETWEEN(SYSDATE,
p_birth_date)/12)
INTO v_age
FROM sys.dual;
RETURN(v_age); -- result of function
END;
TRUE
FALSE
ISAD211 8
Cursors
SQL query delivers an indivisible SET of
rows
Cursor allows row by row processing of
the result set of a query
Think of a cursor as a local table of
results
Read one record or row at a time
Do something with it
ISAD211 9
Cursor operations
DECLARE
specify query to populate cursor
OPEN
run query to populate cursor
FETCH
get a 'row' from the cursor
CLOSE
ISAD211 10
DECLARE title_cur cursor
CURSOR title_cur IS
SELECT title
FROM books;
ISAD211 11
OPEN title_cur;
Serpent's Reach
Faded Sun, Kesrith, The
Faded Sun, Shon'jir, The
…
Titans, The
Black Tulip, The
ISAD211 12
FETCH title_cur INTO v_title;
Serpent's Reach
Faded Sun, Kesrith, The
Faded Sun, Shon'jir, The
v_title
… Serpent's Reach
Titans, The
Black Tulip, The
ISAD211 13
FETCH title_cur INTO v_title;
Serpent's Reach
Faded Sun, Kesrith, The
Faded Sun, Shon'jir, The
v_title
… Faded Sun, Kesrith, The
Titans, The
Black Tulip, The
ISAD211 14
FETCH title_cur INTO v_title;
Serpent's Reach
Faded Sun, Kesrith, The
Faded Sun, Shon'jir, The
v_title
… Faded Sun, Shon'jir, The
Titans, The
Black Tulip, The
ISAD211 15
FETCH title_cur INTO v_title;
Serpent's Reach
Faded Sun, Kesrith, The
Faded Sun, Shon'jir, The
v_title
… Titans, The
Titans, The
Black Tulip, The
ISAD211 16
FETCH title_cur INTO v_title;
Serpent's Reach
Faded Sun, Kesrith, The
Faded Sun, Shon'jir, The
v_title
… Black Tulip, The
Titans, The
Black Tulip, The
ISAD211 17
EXIT WHEN title_cur
%NOTFOUND;
Serpent's Reach
Faded Sun, Kesrith, The
Faded Sun, Shon'jir, The
v_title
…
Titans, The
Black Tulip, The
ISAD211 18
Cursor example
DECLARE
v_new_title VARCHAR2(60);
v_title VARCHAR2(60);
v_length INTEGER;
v_char CHAR(1);
CURSOR c_title IS
SELECT title
FROM books;
BEGIN
OPEN c_title;
LOOP
FETCH c_title INTO v_title;
EXIT WHEN c_title%NOTFOUND;
v_length := LENGTH(v_title);
v_new_title := '';
FOR i IN 1..v_length LOOP
v_char := SUBSTR(v_title, i, 1);
IF UPPER(v_char) IN ('A', 'E', 'I', 'O', 'U')
THEN
v_char := '*';
END IF;
v_new_title := v_new_title||v_char;
END LOOP;
DBMS_OUTPUT.PUT_LINE(v_new_title);
END LOOP;
CLOSE c_title;
END;
ISAD211 19
Listing stored code in
SQL Developer
ISAD211 20
PL/SQL exception handling
Enables‘bulletproofing’ of code to
handle run-time errors and retain
processing control
ISAD211 21
Example (modified from Oracle
documentation)
DECLARE
v_pe_ratio NUMBER(3,1);
BEGIN
SELECT price / earnings -- potential division-by-zero error
INTO v_pe_ratio
FROM stocks
WHERE symbol = 'XYZ';
INSERT INTO stats (symbol, ratio)
VALUES ('XYZ', v_pe_ratio);
COMMIT;
EXCEPTION -- exception handlers begin
WHEN ZERO_DIVIDE THEN -- handles 'division by zero' error
INSERT INTO stats (symbol, ratio) VALUES ('XYZ', NULL);
COMMIT;
WHEN OTHERS THEN -- handles all other errors
ROLLBACK;
END; -- exception handlers and block end here
ISAD211 22
Advantages
Need to code multiple checks
removed
A single exception handler will
process all errors of a given type
ISAD211 23
Some common pre-defined
PL/SQL exceptions
INVALID_NUMBER
conversion of a character string into a number fails
(ORA-01722)
NO_DATA_FOUND
A SELECT INTO statement returns no rows (ORA-
01403)
VALUE_ERROR
An arithmetic, conversion, truncation, or size-
constraint error occurs. For example, when your
program selects a column value into a character
variable, if the value is longer than the declared
length of the variable (ORA-06502)
PROGRAM_ERROR
PL/SQL has an internal problem (ORA-06501)
ISAD211 24
Database triggers revisited
coded in PL/SQL
critical for data integrity
server-side integrity ensures
more robust database than
client-side validation
ISAD211 25
Client-side integrity
integrity checks
application database
database is
ISAD211 vulnerable 26
Server-side integrity
integrity checks
application database
database is
ISAD211 protected 27
Issues
Data sent to the server before being
checked for integrity increases network
traffic and server load
Perform simple client-side 'belt and
braces' integrity checking, e.g. check
for required fields
Opaque server error messages need to
be communicated sensibly to the
application/user
ISAD211 28
Server- & client-side integrity
integrity checks
integrity checks
application database
DB & network
ISAD211 load is reduced 29
Example trigger
CREATE OR REPLACE TRIGGER trg_clients
BEFORE INSERT OR UPDATE OF dob ON clients FOR EACH ROW
BEGIN
IF INSERTING THEN
SELECT seq_client_id.nextval
INTO :NEW.client_id
FROM sys.dual;
END IF;
IF MONTHS_BETWEEN(SYSDATE,:NEW.dob) < 18*12 THEN
/* Issue error code (ORA-20000) and message */
RAISE_APPLICATION_ERROR(-20000, 'Client must be at
least 18 years of age');
END IF;
END;
ISAD211 30
References
PLSQL by Example on Portal
ISAD211 31
Exercise
Write a PL/SQL function (AVERAGE_PRICE) to
calculate the average retail price of books
(rounded to the nearest penny) in the
Harrington books table where the retail price is
above an amount specified as a parameter.
You should use a cursor.
Test your results against
SELECT ROUND(AVG(retail_price),2)
FROM books
WHERE retail_price > &threshold
ISAD211 32