Programming in Oracle With PL/SQL: Procedural Language Extension To SQL
Programming in Oracle With PL/SQL: Procedural Language Extension To SQL
with PL/SQL
1
PL/SQL
• Allows using general programming tools
with SQL, for example: loops,
conditions, functions, etc.
• This allows a lot more freedom than
general SQL, and is lighter-weight than
JDBC.
• We write PL/SQL code in a regular file,
for example PL.sql, and load it with @PL
in the sqlplus console.
2
PL/SQL Blocks
• PL/SQL code is built of Blocks, with a unique
structure.
• There are two types of blocks in PL/SQL:
1. Anonymous Blocks: have no name (like scripts)
• can be written and executed immediately in SQLPLUS
• can be used in a trigger
2. Named Blocks:
• Procedures
• Functions
3
:Anonymous Block Structure
DECLARE (optional)
/* Here you declare the variables you will use in this
block */
BEGIN (mandatory)
/* Here you define the executable statements (what
the block DOES!)*/
EXCEPTION (optional)
/* Here you define the actions that take place if an
exception is thrown during the run of this block */
END; (mandatory)
/ A correct completion of a block
will generate the following
Always put a new line with only :message
a / at the end of a block! (This
4 PL/SQL procedure successfully
tells Oracle to run the block)
completed
5
DECLARE
Syntax
identifier
identifier [CONSTANT]
[CONSTANT] datatype
datatype [NOT
[NOT NULL]
NULL]
[:=
[:= || DEFAULT
DEFAULT expr];
expr];
Notice that PL/SQL
Examples includes all SQL types,
…and more
Declare
Declare
birthday
birthday DATE;
DATE;
age
age NUMBER(2)
NUMBER(2) NOT
NOT NULL
NULL :=
:= 27;
27;
name
name VARCHAR2(13)
VARCHAR2(13) :=:= 'Levi';
'Levi';
magic
magic CONSTANT
CONSTANT NUMBER
NUMBER :=:= 77;
77;
valid
valid BOOLEAN
BOOLEAN NOT
NOT NULL
NULL :=
:= TRUE;
TRUE;
6
Declaring Variables with the
%TYPE Attribute
Examples Accessing column sname
in table Sailors
DECLARE
sname Sailors.sname%TYPE;
fav_boat VARCHAR2(30);
my_fav_boat fav_boat%TYPE := 'Pinta';
...
Accessing
another variable
7
Declaring Variables with the
%ROWTYPE Attribute
Declare a variable with the type of a
Accessing
.ROW of a table table
Reserves
reserves_record Reserves%ROWTYPE;
reserves_record.sid:=9;
Reserves_record.bid:=877;
8
Creating a PL/SQL Record
A record is a type of variable which we can
define (like ‘struct’ in C or ‘object’ in Java)
DECLARE
DECLARE
TYPE
TYPE sailor_record_type
sailor_record_type ISIS RECORD
RECORD
(sname
(sname VARCHAR2(10),
VARCHAR2(10),
sid
sid VARCHAR2(9),
VARCHAR2(9),
age
age NUMBER(3),
NUMBER(3),
rating
rating NUMBER(3));
NUMBER(3));
sailor_record
sailor_record
sailor_record_type;
sailor_record_type;
...
...
BEGIN
BEGIN
Sailor
Sailor__record.sname:=‘peter’;
record.sname:=‘peter’;
9 Sailor
Sailor__record.age:=45;
record.age:=45;
Creating a Cursor
• We create a Cursor when we want to go over a
result of a query (like ResultSet in JDBC)
• Syntax Example:
sailorData is a
DECLARE variable that
cursor c is select * from sailors; can hold a
ROW from
sailorData sailors%ROWTYPE; the sailors
table
BEGIN
open c; Here the
first row of
fetch c into sailorData; sailors is
inserted into
10 sailorData
Example
RAD_VALS
DECLARE
DECLARE
Pi
Piconstant
constantNUMBER(8,7)
NUMBER(8,7):= :=3.1415926;
3.1415926;
radius area
areaNUMBER(14,2);
NUMBER(14,2);
cursor
cursorrad_cursor
rad_cursorisisselect
select**from
fromRAD_VALS;
RAD_VALS;
Rad_cursor rad_value
3 rad_valuerad_cursor%ROWTYPE;
rad_cursor%ROWTYPE;
f BEGIN
BEGIN
e 6 open
openrad_cursor;
rad_cursor;
fetch
fetchrad_cursor
rad_cursorinto
intorad_val;
rad_val;
t area:=pi*power(rad_val.radius,2);
8 area:=pi*power(rad_val.radius,2);
c insert
insertinto
intoAREAS
AREASvalues
values(rad_val.radius,
(rad_val.radius,area);
area);
h close
closerad_cursor;
rad_cursor;
END;
END;
Rad_val //
AREAS
Radius
11 Area
3 28.27
DECLARE
DECLARE DECLARE
DECLARE
… … ……
cursor
cursorrad_cursor
rad_cursorisisselect
select**from
from cursor
cursorrad_cursor
rad_cursorisisselect
select** from
from
;RAD_VALS
;RAD_VALS ;RAD_VALS
;RAD_VALS
;;rad_value
rad_valuerad_cursor%ROWTYPE ;;rad_value
rad_cursor%ROWTYPE rad_valueRAD_VALS.radius%TYPE
RAD_VALS.radius%TYPE
BEGIN
BEGIN BEGIN
BEGIN
;open
;openrad_cursor ;open
rad_cursor ;openrad_cursor
rad_cursor
;fetch
;fetchrad_cursor
rad_cursorinto
intorad_val
rad_val ;fetch
;area:=pi*power(rad_val.radius,2) ;fetchrad_cursor
rad_cursorinto
intorad_val
rad_val
;area:=pi*power(rad_val.radius,2) ;area:=pi*power(rad_val,2)
;area:=pi*power(rad_val,2)
,insert
,insertinto
intoAREAS
AREASvalues
values(rad_val.radius
(rad_val.radius ;insert
;);)area ;insertinto
intoAREAS
AREASvalues
values(rad_val,
(rad_val,area)
area)
area …
… …
…
DECLARE
DECLARE DECLARE
DECLARE
…… … …
;cursor
;cursorrad_cursor
rad_cursorisisselect
select**from
fromRAD_VALS
RAD_VALS cursor
cursorrad_cursor
rad_cursorisisselect
selectradius
radiusfrom
from
;rad_value RAD_VALS%ROWTYPE
;rad_value RAD_VALS%ROWTYPE ;RAD_VALS
;RAD_VALS
BEGIN ;;rad_value
BEGIN rad_valueRAD_VALS.radius%TYPE
RAD_VALS.radius%TYPE
;open
;openrad_cursor
rad_cursor BEGIN
BEGIN
;fetch
;fetchrad_cursor
rad_cursorinto
intorad_val ;open
rad_val ;openrad_cursor
rad_cursor
;area:=pi*power(rad_val.radius,2) ;fetch
;area:=pi*power(rad_val.radius,2) ;fetchrad_cursor
rad_cursorinto
intorad_val
rad_val
insert
insertinto
intoAREAS
AREASvalues
values(rad_val.radius,
(rad_val.radius, ;area:=pi*power(rad_val,2)
;area) ;area:=pi*power(rad_val,2)
;area) ;insert
… ;insertinto
intoAREAS
AREASvalues
values(rad_val,
(rad_val,area)
area)
… …
12 …
Explicit Cursor Attributes
Obtain status information about a
.cursor
. . .
IF rating > 7 THEN
v_message := 'You are great';
ELSIF rating >= 5 THEN
v_message := 'Not bad';
ELSE
v_message := 'Pretty bad';
END IF;
. . .
16
Suppose we have the following
:table
create table mylog( mylog
who varchar2(30), logon_num who
logon_num number
); 3 Peter
if SQL%ROWCOUNT = 0 then
insert into mylog values(user, 1);
end if;
commit;
END;
/
20
Loops: Simple Loop
create table number_table(
num NUMBER(10)
);
DECLARE
i number_table.num%TYPE := 1;
BEGIN
LOOP
INSERT INTO number_table
VALUES(i);
i := i + 1;
EXIT WHEN i > 10;
END LOOP;
END;
21
Loops: Simple Cursor Loop
create table doubles(
num NUMBER(10)
);
DECLARE
cursor c is select * from number_table;
cVal c%ROWTYPE;
BEGIN
open c;
LOOP
fetch c into cVal;ل11لىا11طر ا11لاول س11 ارسا,I;`hcval
EXIT WHEN c%NOTFOUND;
insert into doubles values(cVal.num*2);
END LOOP;
22
END;
Loops: FOR Loop
DECLARE
i number_table.num%TYPE;
BEGIN
FOR i IN 1..10 LOOP
INSERT INTO doubles VALUES(i);
END LOOP;
END;
BEGIN
for num_row in c loop
insert into doubles
values(num_row.num*2);
end loop;
END;
/
DECLARE
TEN number:=10;
i number_table.num%TYPE:=1;
BEGIN
WHILE i <= TEN LOOP
INSERT INTO doubles
VALUES(i);
i := i + 1;
END LOOP;
END;
25
Printing Output
• You need to use a function in the
DBMS_OUTPUT package in order to print to the
output
• If you want to see the output on the screen, you
must type the following (before starting):
set serveroutput on format wrapped size 1000000
• Then print using
– dbms_output. put_line(your_string);
– dbms_output.put(your_string);
26
Input and output example
set serveroutput on format wrap size 1000000
ACCEPT high PROMPT 'Enter a number: '
DECLARE
i number_table.num%TYPE:=1;
BEGIN
dbms_output.put_line('Look Friend, I can print from PL/SQL!!!');
WHILE i <= &high LOOP
dbms_output.put_line(‘i=‘||i);
INSERT INTO number_table
VALUES(i);
i := i + 1;
END LOOP;
END;
27
Reminder- structure of a block
DECLARE (optional)
/* Here you declare the variables you will use in this
block */
BEGIN (mandatory)
/* Here you define the executable statements (what
the block DOES!)*/
EXCEPTION (optional)
/* Here you define the actions that take place if an
exception is thrown during the run of this block */
END; (mandatory)
/
28
Trapping Exceptions
• Here we define the actions that should
happen when an exception is thrown.
• Example Exceptions:
– NO_DATA_FOUND
– TOO_MANY_ROWS
– ZERO_DIVIDE
• When handling an exception, consider
performing a rollback
29
DECLARE
num_row number_table%ROWTYPE;
BEGIN
select *
into num_row
from number_table;
dbms_output.put_line(1/num_row.num);
EXCEPTION
WHEN NO_DATA_FOUND THEN
dbms_output.put_line('No data!');
WHEN TOO_MANY_ROWS THEN
dbms_output.put_line('Too many!');
WHEN OTHERS THEN
dbms_output.put_line(‘Error’);
30 end;
User-Defined Exception
DECLARE
e_number1 EXCEPTION;
cnt NUMBER;
BEGIN
select count(*)
into cnt
from number_table;
EXCEPTION
WHEN e_number1 THEN
dbms_output.put_line('Count = ‘||
31 cnt);//print count=1
end;
Functions and Procedures
• Up until now, our code was in an
anonymous block
• It was run immediatelyف ورا
• It is useful to put code in a function or
procedure so it can be called several
times
• Once we create a procedure or function
in a Database, it will remain until
deleted (like a table).
32
Creating Procedures
CREATE
CREATE [OR
[OR REPLACE]
REPLACE] PROCEDURE
PROCEDURE
procedure_name
procedure_name
[(parameter1
[(parameter1 [mode1]
[mode1] datatype1,
datatype1,
parameter2
parameter2 [mode2]
[mode2] datatype2,
datatype2,
.. .. .)]
.)]
IS|AS
IS|AS
PL/SQL
PL/SQL Block;
Block;
• Modes:
– IN: procedure must be called with a value for the parameter.
Value cannot be changed
– OUT: procedure must be called with a variable for the
parameter. Changes to the parameter are seen by the user
(i.e., call by reference)
– IN OUT: value can be sent, and changes to the parameter
are seen by the user
33
• Default Mode is: IN
?Example- what does this do
Table mylog create
create or
or replace
replace procedure
procedure
num_logged
num_logged
_logon (person
who (person IN
IN mylog.who%TYPE,
mylog.who%TYPE,
num num
num OUT
OUT mylog.logon_num%TYPE)
mylog.logon_num%TYPE)
IS
IS
BEGIN
3 Pete BEGIN
select
select logon_num
logon_num
into
into num
num
from
from mylog
4 John where
mylog
where who
who == person;
person;
END;
END;
//
2 Joe
34
Calling the Procedure
declare
declare
howmany
howmany mylog.logon_num%TYPE;
mylog.logon_num%TYPE;
begin
begin
num_logged(
num_logged(''ORA71398',howmany);
ORA71398',howmany);
dbms_output.put_line(howmany);
dbms_output.put_line(howmany);
end;
end;
//
35
Errors in a Procedure
• When creating the procedure, if there are
errors in its definition, they will not be shown
• To see the errors of a procedure called
myProcedure, type
SHOW ERRORS PROCEDURE myProcedure
in the SQLPLUS prompt
• For functions, type
SHOW ERRORS FUNCTION myFunction
36
Creating a Function
• Almost exactly like creating a
procedure, but you supply a return type
CREATE
CREATE [OR
[OR REPLACE]
REPLACE] FUNCTION
FUNCTION
function_name
function_name
[(parameter1
[(parameter1 [mode1]
[mode1] datatype1,
datatype1,
parameter2
parameter2 [mode2]
[mode2] datatype2,
datatype2,
.. .. .)]
.)]
RETURN
RETURN datatype
datatype
IS|AS
IS|AS
PL/SQL
PL/SQL Block;
Block;
37
A Function
create
create or
or replace
replace function
function
rating_message(rating
rating_message(rating IN IN NUMBER)
NUMBER)
return
return VARCHAR2
VARCHAR2
AS
AS NOTE THAT YOU
BEGIN DON'T SPECIFY THE
BEGIN SIZE
IF
IF rating
rating >> 77 THEN
THEN
return
return 'You
'You are
are great';
great';
ELSIF
ELSIF rating
rating >=>= 55 THEN
THEN
return
return 'Not
'Not bad';
bad';
ELSE
ELSE
return
return 'Pretty
'Pretty bad';
bad';
END
END IF;
IF;
END;
END;
//
38
Calling the function
declare
declare
paulRate
paulRate number
number :=9;
:=9;
Begin
Begin
dbms_output.put_line(rating_Message(paulRate))
dbms_output.put_line(rating_Message(paulRate))
;;
end;
end;
//
39
:Creating a function
create or replace function squareFunc(num in number)
return number
is
BEGIN
return num*num;
End;
/
41
Triggers
• Triggers are special procedures which
we want activated when someone has
performed some action on the DB.
• For example, we might define a trigger
that is executed when someone
attempts to insert a row into a table,
and the trigger checks that the
inserted data is valid
42
CREATE-TRIGGER
44
CREATE TABLE T4 (a number, b
CHAR(10));
CREATE TABLE T5 (c CHAR(10), d
number );
46
-- create a main table and its shadow table
CREATE TABLE parts (pnum NUMBER(4), pname
VARCHAR2(15));
CREATE TABLE parts_log (pnum NUMBER(4), pname
VARCHAR2(15));
CREATE TRIGGER parts_trig BEFORE INSERT ON parts
FOR EACH ROW
DECLARE
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN INSERT INTO parts_log VALUES(:new.pnum,
:new.pname);
COMMIT;
47 END;
CREATE TABLE emp_audit ( empno NUMBER(6),
up_date DATE, new_sal NUMBER(8,2), old_sal
NUMBER(8,2),user1 varchar2(50));
48
ALTER TRIGGER trigger name ENABLE
49
CREATE TABLE empauditlog ( audit_date DATE, audit_user
;VARCHAR2(20), audit_desc VARCHAR2(20) )
51
DECLARE
CURSOR dept_cur IS
SELECT deptno
FROM dept
;ORDER BY deptno
Employee cursor all employees for a dept number --
CURSOR emp_cur (v_dept_no DEPT.DEPTNO%TYPE) IS
SELECT ename
FROM emp
;WHERE deptno = v_dept_no
BEGIN
FOR dept_rec IN dept_cur LOOP
;dbms_output.put_line('Employees in Department '||TO_CHAR(dept_rec.deptno))
FOR emp_rec in emp_cur(dept_rec.deptno) LOOP
;dbms_output.put_line('...Employee is '||emp_rec.ename)
;END LOOP
;END LOOP
;END
/
52