PL-SQL
1. Introduction to PL/SQL.
2. Decision Making.
3. Loops.
4. Sub –blocks
5. Cursors.
6. Exceptions
8. Stored Procs
9. Stored functions.
10. Packages
11. Managing subprograms
12. Arrays.
13. Database Triggers
14. Advance Trigger concepts.
15. Ref cursor.
16. Dynamic SQL.
1. Introduction to PL/SQL.
• Procedural language SQL
• Complex processing like loops and IF condition.
• Also known as programming language of ORACLE
• PL SQL can be used for processing recordsets.(cursors) ,resultset.
• It can be used in SQL PLUS , oracle Forms, oracle Reports , oracle
Menus, oracle graphics.
Declare
Declarative section.
Begin
End
/*Program*/
Begin
--------
--------
Begin
--------
--------
Begin
--------
--------
End;
----------
-----------
End;
---------
---------
End;
Forward slash comes outside the outermost block.
No limit for block within a block. This is known as Block level language.
In a PL/SQL block, SQL commands like insert ,delete, rollback, commit,
select are used.
• DDL commands not allowed. eg. Create , drop table are not allowed.
• DCL commands not allowed eg. Grant , revoke cannot be done
• Create a table at SQL prompt
Create table tempp123
FIR number(8),
SEC varchar2 (25)
);
Anonymous Blocks
1.
Begin
Insert into tempp123 values(1,’Hello’);
Insert into tempp123 values(2,’Hello’);
End;
SQL> Insert into tempp123 values (1,’Hello’);
SQL> Insert into tempp123 values (2,’Hello’);
SELECT * FROM TEMPP123;
2. Declare
X number (4);
Begin
X := 100;
Insert into tempp123 Values (X, 'Hello');
End;
Select * from tempp123;
IN the above program, X is declared between Declare and Begin.Variable
declaration must be between Declare and Begin. “ : = ” is known as the
assignment operator.
3. cl scr
Delete from tempp123;
Declare
X number (4):= 100;
Begin
Insert into tempp123
Values (X, ‘Hello’);
End;
The entire program goes into the buffer.
4.
Declare
X number(4);
Begin
X := &salary;
Insert into tempp123
Values (X, ‘Hello’);
End;
Here value of salary is inputted by user. Value is asked for during
compilation and not at runtime.
5. Select * from tempp123;
Declare
X char(15) ;
Begin
X := ‘&ename’;
Insert into tempp123
Values (1, X);
End;
Enter the name of employee : Jack
Or
Enter the name of employee: 1056 /*This is not possible coz number to char
conversion is implicit but char to number is not implicit*/
7. Declare
X constant number (4):= 100;
Begin
Insert into tempp123
Values (X, ‘Hello’);
End;
Constant variable value can’t be changed anywhere in the program.
8. Declare
X number (8);
Begin
Select sal into X
From emp
Where fname like ‘Mandar’;
Insert into tempp123
Values (X, ‘Mandar’);
End;
Value of sal from emp table is transferred into tempp123 table and
displayed. Select in some variable name is allowed .
Output FIR SEC
5000 King
9. Declare
X number(8);
Y varchar2(35);
Hra number(6,2);
Begin
Select sal , job into X ,Y
From emp
Where lower(fname) like ‘mandar’;
Hra:= 0.10 * X ;
Insert into tempp123 Values (X, ‘Mandar’);
Insert into tempp123 Values (Hra, Y);
dbms_output.put_line (‘Salary of Mandar is ’|| X ||’and Hra is =’ ||Hra);
End;
dbms_output.put_line can be used to test program. It is not PL/SQL
command. It’s a package developed by ORACLE .In the
“dbms_output.put_line (X || ‘King’ || Hra || ‘ ‘ || Y);” number to char
conversion is implicit . If date is there then TO_CHAR is required. For this
stmnt to work:
SQL> SET SERVEROUTPUT ON
Case 1
Declare
X number (4);
Case 2
10. Declare
X emp.sal%type;
Y emp.job%type;
Begin
Select sal,job into x ,y
from emp
where fname like ‘Mandar’;
Insert into tempp123
Values (x, y);
End;
“ x emp.sal%type ” defines that datatype of x is same as that of the
datatype of sal in emp table.
11. Declare
x emp% rowtype;
Begin
Select * into x
From emp
Where fname like ‘Mandar’;
Insert into tempp123
Values (x.sal, x.job);
End;
/
fname sal job
rowtype is used to store entire row
x.fname
x.sal x.job
Create user-defined structure (RECORD) in PL/SQL:
Declare
Type pqr is record
a emp.sal%type,
b emp.job%type
);
x pqr;
Begin
Select sal, job into x
From emp
Where fname = ‘Mandar’;
Insert into tempp123 values (x.a, x.b);
End;
Create table emp_profile
(empno number,sal number(8),job varchar2(30));
Declare
Type abc is record
a emp.sal%type,
b emp.job%type
);
Type emp_profile_pqr is record
l number(4),
m abc
);
x emp_profile_pqr ;
Begin
Select empno, sal, job into x.l,x.m.a, x.m.b
From emp
Where fname like ‘Mandar’;
Insert into emp_profile values (x.l,x.m.a, x.m.b);
End;
2. DECISION MAKING
IF STMNT:
1. Declare
X number (8);
Begin
Select sal into x
from emp
Where fname like ’Mandar’;
If X>4000 then
Insert into tempp123 values (X,’HIGH SAL’);
else
insert into tempp123 values (X,’LOW SAL’);
end if;
End;
IF – ELSIF
2. Declare
X number (8);
Begin
Select sal into X
From EMP
Where fname like ’Mandar’;
IF X>30000 then
Insert into tempp123 values (x,’HIGH SAL’);
elsif X<30000 and X>4000 then
Insert into tempp123 values (x,’MED SAL’);
else
Insert into tempp123 values (x,’low SAL’);
END IF;
End;
3. Declare
X Boolean; /* boolean can be used only in PL SQL –Multiline
comments */
Begin
X:=false; --edited by abc (single line comment)
If X then
Insert into tempp123 Values (1,’positive’);
Elsif not X then
Insert into tempp123 values (0,’negative’);
End if;
End;
LOOPS
WHILE LOOP :
1. Declare
X number (4) := 1;
Begin
While X <10
Loop
Insert into tempp123
Values (X , ‘Hello’);
X:=x+1;
EXIT;
End loop;
End;
Note: Explain EXIT keyword.
DO WHILE LOOP:
5. Declare
X number(4) := 1;
Begin
Loop
Insert into tempp123
Values (X, ‘Do-While’);
Exit when X>5;
X := X+1;
End loop;
End;
Executes the loop atleast once.
FOR LOOP:
• Automatic incrementation of variable.
• For variable need not be declared.
• Step value cannot be changed .Always increments by 1.
If u want to change step value then use ‘while’ loop.
6. Declare
Begin
For X in 1..10
Loop
Insert into tempp123
Values (X, ‘Hello’);
End loop;
End;
• Here X is only read only variable u can’t initialize and assign value to
it.
• 1.. 10 should contain exactly two dots only.
7. Declare
X number(4):= 100;
Begin
Insert into tempp123
Values (X, ‘before for’);
For X in 1..10
Loop
Insert into tempp123
Values (X, ‘For-Loop’);
End loop;
Insert into tempp123
Values (X, ‘after for’);
End;
Output FIR SEC
100 before for
1 Hello
: “
9 “
100 after for
8. Declare
Y number (4):= 10;
Z number (4):= 20;
Begin
For X in Y..Z
Loop
Insert into tempp123
Values (X, ‘Hello’);
End loop;
End;
For more user friendly program we can use:
For X in X…&Y // additional dot is taken as delimiter
output Enter X: 16
Y: 25
OR
For X in &X ..&Y // blank space in between also acts as a delimiter.
Declare
Y number(4) ;
Z number(4);
Begin
For X in &Y...&Z
Loop
Insert into tempp123
Values (X, ‘Hello’);
End loop;
End;
10. For X in 1.5..9.3
It rounds it to 2 and 9 and then execute.
Begin
for X in 1..10
loop
for Y in 1..X ----INNER LOOP
loop
Insert into tempp123
Values (X, ‘Hello’);
End loop;
End loop;
End;
Note: -- single comment (don’t put & in comment)
/*multilane comment*/
GOTO stmnt:
• Conditional or unconditional transfer of control.
1. Declare
X number (4):= 1;
Begin
Insert into tempp123
Values (X, ‘A’);
Goto abc;
<<pqr>>
Insert into tempp123
Values (X, ‘B’);
X := X+1;
<<abc>>
Insert into tempp123
Values (X, ‘C’);
If X < 3 then
Goto pqr;
End if;
End ;
output FIR SEC
1 A
1 C
1 B
2 C
2 B
3 C
NOTE: If large no.of GOTO stmnt in program then it is called SPAGHETTI
CODE.
Practical use: when u’ve large no. of nested loops use goto stmnt to come
out.
Rules fro GOTO stmnt:
• Cannot transfer control into a loop. Reverse is allowed.
• Cannot transfer control into IF condition . Reverse is allowed .
• GOTO should always transfer control to some executable
stmnt.Same things hold true for if..endif condition.
SUB – BLOCKS
1. Declare
X number (4):= 1;
Begin
Insert into tempp123
Values (X, ‘before sub’);
Declare
Y number (4):= 2;
Begin
Insert into tempp123
Values (X, ‘in sub BLOCK’);
X: = X+Y;
End;
Insert into tempp123
Values (X, ‘after sub’);
End;
Output FIR SEC
1 before sub
1 in sub
3 after sub
• Parent cannot access child’s variables . Reverse is allowed.
• Child can alter parents variables (will affect globally).
2. Declare
X number (4):= 1;
Begin
Insert into tempp123
Values (X, ‘before sub’);
Declare
X number (4):= 2;
Begin
Insert into tempp123
Values (X, ‘in sub’);
End;
Insert into tempp123
Values (X, ‘after sub’);
End;
output FIR SEC
1 before sub
2 in sub
1 after sub
3. <<abc>>
Declare
X number (4) := 1;
Begin
Declare
X number (4) := 2;
Begin
Insert into tempp123
Values (abc.X, ‘in sub’); -- this will access parents X.
end;
end;
• To access global X use labels.
• One child cannot access another child’s variable.
CURSORS(V.V.V IMP)
Cursors are of two types:
1. Implicit Cursor:
• Oracle created
• To check the status of last DML stmnt(To check whether successful
or not)
• Name of implicit cursor is SQL
• Maintain logs / audit trails of all DML operations
1. Declare
X number(4);
Begin
Update emp set sal = sal+1 where deptno = 110;
If SQL%found then
X:= SQL%rowcount;
Insert into tempp123 values (X,’updated’);
End if;
End;
Sql%found returns a true value if the last DML is successful.
Output 3 updated
2. Declare
X number(4);
Begin
Delete from EMP where deptno = 20;
If SQL%found then
X:= SQL%rowcount;
Insert into tempp123 values (X,’deleted’);
End if;
End;
Output 2 deleted
3. Declare
X number(4);
Begin
Insert into emp select * from semp; --semp structure similar to emp.
If SQL%found then
X := SQL%rowcount;
Insert into tempp123 values (X,’inserted’);
End if;
End;
Output 4 inserted
• In single insert all rows are inserted to emp .
2. Explicit cursor:
• It’s a type of variable.
• Used for handling multiple rows and process them row by row.
• Used for storing data temporarily.
• It’s a memory area .
• It is used for record locking.
1. Declare
Cursor C1 is select * from emp where deptno=10;
X emp%rowtype;
Begin
Open C1; ---will open the cursor and will populate it with the above
select statement
Loop
Fetch C1 into X;
Exit when C1%notfound; ---%notfound returns true if the last fetch is
unsuccessful
Insert into tempp123
Values (X.empno, X.fname);
End loop;
Close C1; ---will free up the memory used by c1
End;
Cursor attributes:-
a) %notfound r
b) %found .i.e TRUE if last fetch
is successful & false if it is unsuccessful
c) %isopen returns true value whenever cursor is open
d) %rowcount no.of rows fetched by cursor so far
Declare
Cursor C1 is select * from emp;
X emp%rowtype;
Y number;
Begin
Open C1;
Loop
Fetch C1 into X;
Exit when C1%notfound;
insert into tempp123
Values (X.empno, X.fname);
End loop;
Y := C1%rowcount;
Dbms_output.put_line(‘value of y is ‘||Y);
Close C1;
End;
-------
if C1% isopen then
close C1;
endif;
Before opening cursor check if it is already open then close it & again it
can be opened. This concept is used for Resetting the cursor pointer.
Steps in cursor operation:
• Declaration of variable X (intermediate variable for fetching row)
• Open cursor (fires the select statement in the cursor and populates
the data).
• Fetch one row at a time to X from cursor
• Include proper condition to exit;otherwise it goes in an infinite loop.
• Close cursor to free memory in RAM.
FOR LOOP Cursor:-
8. Declare
Cursor C1 is select fname, sal from emp;
Begin
For X in C1
Loop
Insert into tempp123 values(X.sal, X.fname);---ACTION
End loop;
End;
Advantages of a For Loop Cursor:-
1. Here we do not declare the for variable, it will have same structure of
C1.
2. No need to open C1. No need to fetch manually its automatic.
3. Exit condition also not required.
4. The for loop cursor automatically gets destroyed .No need of close
C1.
Declare
Cursor C1 is select fname, sal from emp;
Begin
For X in C1
Loop
Insert into tempp123 values(X.sal, X.fname);
End loop;
End;
Output tempp123
10. Declare
Cursor C1 is select * from emp
where deptno= &deptnum;
Begin
For X in C1
Loop
Insert into tempp123 values (X.sal, X.fname);
End loop;
End;
This is static to make it dynamic proc++, projava.
OV7 onwards parameters can be passed to cursor.
11. Declare
Cursor C1 (dd number)
is select * from emp
Where deptno=dd;
Begin
For X in C1(10)
Loop
Insert into tempp123 values (X.sal, X.fname);
End loop;
For X in C1(30)
Loop
Insert into tempp123 values (X.sal, X.fname);
End loop;
End;
Declare
cursor C1(dd number)
is select * from emp
where deptno=dd;
Begin
For X in C1(&d1)
Loop
Insert into tempp123 values (X.sal, X.fname);
End loop;
For X in C1(&d2)
Loop
Insert into tempp123 values (X.sal, X.fname);
End loop;
End;
13. Declare
Cursor C1 (dd number, ss number)
Is select * from EMP
Where deptno=dd and sal>ss;
Begin
For X in C1(10,29000)
Loop
Insert into tempp123 values (X.sal, X.fname);
End loop;
End;
14. Default arguments in a cursor:-
Declare
cursor C1(dd number, ss number default 9000)
is select * from emp
where deptno=dd and sal>ss;
Begin
For X in C1(10)
Loop
Insert into tempp123 values(X.sal, X.fname);
End loop;
End;
15. Declare
Cursor C1 is select fname, sal+1 salary
from emp;
Begin
For X in C1
Loop
Insert into tempp123 values(X.salary, X.fname);
End loop;
End;
C1
A 5001
B 6001
C 7001
D 8001
E 9001
• In cursor defn if u’ve computed field,or an function like sum,ltrim
then alias should be given so as to refer that column.
If alias not given then u cannot refer that field,but block will still
execute.
17. Declare
Cursor C1 is select * from dept;
Cursor C2 is select * from emp;
Begin
For X in C1
Loop
For Y in C2
Loop
If X.deptno = Y.deptno then
Insert into tempp123 values(Y.empno, X.dname);
End if;
End loop;
End loop;
End;
C2 emp
EMPNO ENAME SAL DEPTNO
1 A 5000 1
2 B 6000 1
3 C 7000 1
4 D 8000 2
5 E 9000 2
C1 dept
Deptno Dname Loc
1 Trn Mumbai
2 Exp Delhi
3 Mrktng Calcutta
• There is no upper limit on no.of cursors opened simultaneously.
• INIT.ORA startup file of oracle server, text file around 350
parameters. One of the parameters is
OPEN_CURSORS = 250 set to whatever values it allows that many
cursors to open simultaneously. Default value is 25.
Note: For each deptno in C1 open C2 , go through C2, close C2, advance
C2, C1 pointers, open C2 continue to slow.
Output:
1 trn
2 trn
3 trn
4 exp
5 exp
Faster programs:
18.
Declare
Cursor C1 is select * from dept;
Cursor C2(dd number) is select * from emp
Where deptno=dd;
Begin
For X in C1
loop
For Y in C2 (X.deptno) -- only those rows with dept no in C2 hence
faster.
Loop
Insert into tempp123 values(Y.empno, X.dname);
End loop;
End loop;
End;
Here no unnecessary comparisons of records .
19. Fastest:
Declare
Cursor C1 is select empno, dname
From emp, dept
Where dept.deptno = emp.deptno;
Begin
For X in C1
Loop
Insert into tempp123 values(X.empno, X.dname);
End loop;
End;
gives u same output but is much more faster than before two ways.
20. Declare
Cursor C1 is Select * from emp;
Begin
For X in C1
Loop
If X.sal > 7000 then
Update emp set sal= sal+1;
End if;
End loop;
End;
Sal column of emp table is updated.
21. Declare
Cursor C1 is select * from emp for update;
Begin
For X in C1
Loop
If X.sal > 7000 then
Update emp set sal = sal +1 where current of C1;
End if;
End loop;
End;
• For update record locking. Manual locking of all the rows.
22. Declare
Cursor C1 is select * from emp for update;
Begin
For X in C1
Loop
If X.sal > 47000 then
Delete from emp where current of C1;
End if;
End loop;
End;
ARRAYS
• To store multiple elements of the same datatype.
• Temporary table
• In PL SQL arrays are single dimension only (multidimension arrays
not allowed in OV7 but OV7 onwards it allows).
• Can ‘ve array only for a scalar datatype. Composite datatype not
allowed. Cannot‘ve an array of structure in OV7./ But OV7 onwards it
allows.
10 20 30
A
• In PL SQL subscript has to be binary integer for variables (for
constants base 10 is allowed). In above A(1),A(2),A(3).
• Array size is dynamic. Add elements array size increases
automatically. Remove elements array size decreases automatically.
EXCEPTION
Exceptions are of foll. Types:-
1. Predefined Exception.
2. User defined Exception.
3. Pragma Exception init.
4. Raise Application error.
Declare
Begin
end
Declare
Begin
====
Exception when too_many_rows then
END;
A. Predefined exception:
Oracle created (already available in the system).
Automatically invoked as and when specific error takes place
1 Declare
X number(8);
Begin
Select sal into X from emp
Where fname = ‘Mandar’;
Insert into tempp123 values (X, ‘King’);
Exception when too_many_rows then
Insert into tempp123 values (1, ‘Too many rows Error’); -- error
handling routine
End;
update emp set fname ='Mandar' where fnAME='raj';
o/p
FIR SEC
1 Hello
Note:-
Within the error handling routine, all PL SQL stmnts are allowed.
Control can’t be transferred from error handling routine to any other
part of the block.
2. Declare
X number (8);
Begin
Select sal into X from emp
Where fname = ‘Jack’;
Insert into tempp123 values (X, ‘Jack’);
Exception when no_data_found then
Insert into tempp123 values (1, ‘no data found’); --error handling
routine
When others then
Insert into tempp123 values (2,’others’);
End;
3. Declare
X number(4);
Begin
X := 10000;----size exceeded
Exception when value_error then
Insert into tempp123 values (1, ‘value error’); --error handling routine
End;
eg: x number(6,2)
x := 1000.786
4. Declare
X number (4);
Begin
X := ‘cal’; --datatype mismatch gives an exception
Exception when value_error then
Insert into tempp123 values (1, ‘value error’); --error handling routine
End;
value_errror : char value in numeric variable in an expression.
5. Declare
X char(4);
Begin
X := 1000;
End;
It doesn’t give error bcoz number to char conversion is implicit.
6. Declare
X number(4);
Begin
Insert into tempp123 values (‘mumbai’, ‘city’);
Exception when invalid_number then /*error char value in numeric
col.*/
Insert into tempp123 values (1, ‘invalid number’); --error handling
routine
End;
/
Note:-- when working with an expression i.e. x number; x:=’abc’; then it
gives a value error,but with an insert statement it gives invalid number.
7. Declare
X number(4) :=10;
Y number(4) :=0;
a number;
b varchar2(32767);---max value in PL/SQL
Begin
X := X/Y;
Exception when zero_divide then
a := sqlcode;
b := sqlerrm;
dbms_output.put_line(‘oracle says’||sqlerrm);
Insert into tempp123 values (a, ‘zero divide’); -- error handling routine
End;
9. Declare
X number(4) :=10 ;
Begin
Insert into tempp123 values (X,’before sub block’);
Declare
X number(4) ;
Begin
X:=10000;
Insert into tempp123 values (X,’in sub’);
Exception when value_error then
Insert into tempp123 values (1, ‘sub error’);
End;
Insert into tempp123 values (X,’After sub’);
Exception when value_error then
insert into tempp123 values (1, ‘main error’);
End;
o/p
FIR SEC
10 before sub
1000 in sub
10 after sub
Can have exception in each block.
10. Remove sub –block exception
Declare
X number (4) :=10 ;
Begin
Insert into tempp123 values (X,’before sub’);
Declare
X number (4) :=10 ;
Begin
X :=10000;
Insert into tempp123 values (X,’in sub’);
End;
Insert into tempp123 values (X,’After sub’);
Exception when value_error then
Insert into tempp123 values (1, ‘main error’);
End;
If sub block exception is removed then search for exception handler in
parent block.
o/p
FIR SEC
10 before sub
1 main error
• Errors can be trapped only between begin and end .
Question:-If error in declare section,then exception can’t handle
it.Then how to handle it?
Declare
X number(4) :=1000000 ;
Begin
Insert into tempp123 values (X,’before sub’);
Declare
X number(4) ;
Begin
X:=1000;
Insert into tempp123 values (X,’in sub’);
Exception when value_error then
Insert into tempp123 values (1, ‘sub error’);
End;
Insert into tempp123 values (X,’After sub’);
Exception when value_error then
insert into tempp123 values (1, ‘main error’);
End;
Declare
X number(4) :=10 ;
Begin
Insert into tempp123 values (X,'before sub');
Declare
X number(4):=100000;
Begin
---X:=100000;
Insert into tempp123 values (X,'in sub');
Exception when value_error then
Insert into tempp123 values (1, 'sub error');
End;
Insert into tempp123 values (X,'After sub');
Exception when value_error then
insert into tempp123 values (1, 'main error');
End;
To take care of this, outside of declare , put dummy parent block.
Few more Predefined exceptions
1. too_many_rows
2. No_data_found
3. Value_error
4. Invalid_number
5. Zero_divide
6 invalid_cursor
Try to close a cursor, when it is not open.
7. cursor_already_open
Try to open a cursor, which is already open.
8. DUP_value on index
Try to insert a duplicate value in a column that has a unique index on it.
9. logon_denied
Logging to oracle with an invalid username and password
10.Program_Error
(Internal PL/SQL error, some files are not installed)
11. Rowtype_mismatch
Fetch c1 into x
(x has a different datatype )
12. storage_error.
(memory problem)
B. User defined exception
• User created
• datatype
• Has to be raised explicitly
• For enforcing business rules.
Eg:
11. Declare
X number(8);
abc exception;
Begin
Select sal into X from emp
Where fname = ‘Mandar’;
if X > 5000 then
raise abc;
end if;
Insert into tempp123 values (X,’<=5000’);
exception when abc then
insert into tempp123 values (X,’>5000’);
end;
o/p 6000 X>5000
600 X<=5000
12. Declare
X number (8) := 10;
abc exception;
Begin
Insert into tempp123 values (X,’before sub’);
Declare
X number(8);
abc exception;
begin
Select sal into X from emp
Where fname = ‘Mandar’;
if X > 5000 then
Raise abc;
End if;
Insert into tempp123 values (X,’in sub’);
Exception when abc then
insert into tempp123 values (X,’sub error’);
end;
Insert into tempp123 values (X,’after sub’);
Exception when abc then
Insert into tempp123 values (X,’main error’);
end;
Remove the exception from the child block
Declare
X number (8) := 10;
abc exception;
Begin
Insert into tempp123 values (X,’before sub’);
Declare
X number(8);
begin
Select sal into X from emp
Where fname = ‘Mandar’;
if X > 5000 then
Raise abc;
End if;
Insert into tempp123 values (X,’in sub’);
end;
Insert into tempp123 values (X,’after sub’);
Exception when abc then
Insert into tempp123 values (X,’main error’);
End;
C. Pragma Exception:- It is used to associate an oracle error number with a
user defined exception
Declare
X number (8);
abc exception;
Pragma exception_init (abc,-01843);
Begin
Select sal into X from emp
Where hiredate = ’10-MMM-95’;
Exception when abc then
Insert into tempp123 values (1, ‘Hello’); --error handling routine
dbms_output.put_line('oracle says errcode is '||sqlcode||’and message
is’ ||sqlerrm);
End;
/
• In above program if error occurs pragmas automatically raise abc
no need of explicitly raising.
Raise Application error:-
Declare
Begin
Delete from emp where empno=99;
If sql%notfound then
Raise_application_error(-20001,’Emp doesn’’t exist’);
End if;
End;
Note:--
Error number :-it can range from –20,000 to –20,999.
Message:-character string upto 2048 bytes.
It is used to create a library of errors
STORED PROCEDURE
• It is a collection of statements.
• Only a single copy is brought into the RAM (program code shared by
all the users) when multiple users execute the same stored proc.
• It’s a pre-compiled code(stored).
• Can be called in SQL Plus, PL SQL Forms, Reports, Menus,
Graphics, JAVA, .NET,VB,
Creating stored Procedures:-
SQL> Create or replace procedure p1
As
Begin
Insert into tempp123 values(1, ‘p1’);
end;
MESSG: Procedure created.
3. SQL> execute P1
It execute stored procedure abc
o/p FIR SEC
1 Hello
4. SQL> Select * from Tempp123;
o/p 1 Hello
TO CALL IN PL SQL :
Declare
=======
Begin
=========
P1 ;
End;
declare
begin
p1;
end;
To call procedure from other schema:
Username. Procedurename
Same way can be called in forms, Reports.
SQL> create or replace procedure p2
as
X number(4) := 10;
Begin
insert into tempp123 values (X, ‘p1’);
insert into tempp123 values (X, ‘p2’);
commit;
End;
• Local variables, cursors, exceptions can be written in stored
procedure.(Same as a PL/SQL Block :-No ddl)
• Can pass parameters.
Creating Procedures with Parameters:-
Actual parameters.---the one we pass in the call
Formal parameters.---the one in the definition.
Types of parameters(vvvvvvimp)
IN- Used to pass values to the procedures OR functions.
Can have a default value.
It is call by reference.
It can be constant or a variable.
OUT- It is used to return values from the Procedures/Functions to the
calling env.
Cannot have defaults values
Must be a variable.
Call by VALUE
IN OUT-Passes a value from the calling environment into the procedure and
a possibly different value from the procedure back to the calling
environment using the same parameter
Call by VALUE
Cannot have defaults values
Must be a variable.
SQL> create or replace procedure p3 (x in number)
As
Begin
Insert into tempp123 values (X, ‘Hello’);
End;
create or replace procedure p3 (x number)
As
Begin
insert into tempp123 values (X, ‘Hello’);
End;
Note:-Never declare sizes for the parameters.
================
Execute p3 (10); // while running
• Parameters passed to stored procedure can be IN , OUT, INOUT
parameters.
Create or replace procedure query_emp
(p_id in emp.empno%type,
p_name out emp.fname%type,
p_salary out emp.sal%type,
p_deptno out emp.deptno%type)
is
Begin
Select fname, sal, deptno
into p_name, p_salary, p_deptno
from emp
Where empno = p_id;
end query_emp;
Variable g_name varchar2(25)
Variable g_sal number
Variable g_deptno number
Execute query_emp(2, :g_name, :g_sal, :g_deptno);
Print g_name
Print g_sal
Print g_deptno
IN OUT Parameters:-
Calling environment FORMAT_PHONE procedure
p_phone_no '(800)633-0575' '8006330575'
CREATE OR REPLACE PROCEDURE format_phone
(p_phone_no IN OUT VARCHAR2)
IS
BEGIN
p_phone_no := '(' || SUBSTR(p_phone_no,1,3) ||
')' || SUBSTR(p_phone_no,4,3) ||
'-' || SUBSTR(p_phone_no,7);
END format_phone;
/
VARIABLE g_phone_no VARCHAR2(15)
BEGIN
:g_phone_no := '8006330575';
END;
/
PRINT g_phone_no
EXECUTE format_phone (:g_phone_no);
PRINT g_phone_no
Examples of stored procedure:-
Create or replace procedure sim_int(p number, t number, r number)
As
si number(6,2);
amt number(7,2);
begin
si := p * t * r / 100;
amt := p + si;
dbms_output.put_line(‘interest =’ || si);
dbms_output.put_line(‘amount =’ || amt);
Exception when value_error then
dbms_output.put_line(‘value too large . Try again’ );
end;
Exec sim_int(5000,3,9);
2. SQL> create or replace procedure delete_emp(x number)
as
y number(4);
abc exception;
Begin
select count(*) into y from emp
where empno = x;
if y = 0 then
raise abc;
end if;
delete from emp where empno = x;
-- commit;
dbms_output.put_line(‘employee deleted successfully’);
Exception when abc then
dbms_output.put_line(‘employee does not exists’);
end;
Now calling the above procedure in another program.
Begin
dbms_output.put_line (‘before procedure’);
delete_emp (1001);
dbms_output.put_line (‘after procedure’ );
End;
Begin
dbms_output.put_line(‘before procedure’);
delete_emp(1);
dbms_output.put_line(‘after procedure’ );
End;
Rollback;
• When you make changes in procedure it has to be recreated.
• Thus we don’t give user direct access to table but through
procedure.
• This is called as procedural encapsulation.
• SQL> select object_name from user_objects -- gives all the
stored ts
Where object_type = ‘PROCEDURE’;
• Now to make changes in stored procedure
SQL> select TEXT from user_source
Where type = ‘PROCEDURE’
And name = ‘SIM_INT’;
SQL> DESC SIM_INT
Describes procedure.
STORED FUNCTIONS
• Global functions(Can be accessed from any Front end)
• Stored in the database in compiled format
• Can be called in PL/SQL , forms, reports, menus, graphics.java,.net
• Can be called at SQL prompt.
1 SQL> create or replace function fabc(y number)
return number
as
Begin
Return y * y;
End;
Function created.
To call the above function in some other PL SQL program:
2. SQL> Declare
x number(4);
begin
x := fabc(10);
Insert into tempp123 values (x, ‘after abc’);
End;
In the above example , we have to equate with some variable because
function returns a value.Hence , it cant be called at SQL prompt.
select fabc(10) from dual;
3. SQL> create or replace function pqr(y number)
return Boolean
As
Begin
if y > 5000 then
Return true;
else
Return false;
end if;
End;
4. SQL> Declare
x number(4);
begin
x := &x;
if pqr(x) then
Insert into tempp123 values (x, ‘>5000’);
else
Insert into tempp123 values (x, ‘<=5000’);
end if;
end;
• If condition is returning Boolean value then directly function name
can be used.
Ex:
create or replace function alltrim(X char)
return char
as
begin
return ltrim(rtrim(x));
end;
CREATE OR REPLACE FUNCTION tax(p_value IN NUMBER)
RETURN NUMBER IS
BEGIN
RETURN (p_value * 0.08);
END tax;
/
SELECT empno, lname, sal, tax(sal)
FROM emp
WHERE deptno = 10;
SELECT empno,lname,sal, tax(sal),deptno
FROM emp
WHERE tax(sal)>(SELECT MAX(tax(sal))
FROM emp WHERE deptno = 30)
ORDER BY tax(sal) DESC;
Restrictions on Calling Functions from SQL Expressions(v.v.imp)
To be callable from SQL expressions, a user-defined
function must:
• Accept only IN parameters
• Accept and return only valid SQL data types, not PL/SQL like boolean
• Functions called from SQL , cannot contain DML statements.
CREATE OR REPLACE FUNCTION dml_call_sql
RETURN NUMBER
IS
BEGIN
INSERT INTO emp(empno, lname,
hiredate, job, sal)
VALUES(111, 'employee 1',
SYSDATE, 'SA_MAN', 2000);
RETURN 1;
END;
/
declare
x number;
begin
x:=dml_call_sql;
end;
Select * from emp where empno=111;
Create or replace function query_empf
(p_id in emp.empno%type,
p_name out emp.lname%type,
p_salary out emp.sal%type,
p_deptno out emp.deptno%type)
return number
is
begin
select lname, sal, deptno
into p_name, p_salary, p_deptno
from emp
where empno = p_id;
return 1;
end query_empf;
Declare
g_name varchar2 (50);
g_sal number;
g_deptno number;
x number;
begin
x:= query_empf(2, :g_name, :g_sal, :g_deptno);
end;
Print g_name;
Print g_sal;
Print g_deptno;
Difference between Procedure and Function( v.v.imp)
1. A Function has to return one value.
2. A Function can be called from sql prompt.
3. Is invoked a part of an expression.
Managing Subprograms
Suppose the EMPLOYEES table is located within the scott schema, and
there is a user named Green.
Green can access the EMPLOYEES table only by way of the QUERY_EMP
procedure that Scott created, which queries employee records.
Definer‘s Rights
Scott provides the EXECUTE object privilege to Green on the QUERY_EMP
procedure.
By default the PL/SQL subprogram executes under the security domain of
the owner.
This is referred to as definer's-rights. Because Scott has direct privileges to
EMPLOYEES table and has created a procedure called QUERY_EMP, Green
can retrieve information from the EMPLOYEES table by using the
QUERY_EMP procedure. Now Green will access the EMPLOYEES table in
scott schema
Imp Note:-
If Green also has an EMPLOYEES table, the QUERY_EMP procedure will
not reference this table but rather the EMPLOYEES table that Scott’s
schema can reference.
Using Invoker's-Rights
The procedure executes with the privileges of the user.
CREATE or replace PROCEDURE query_employee
(P_id IN employees.employee_id%TYPE,
p_name OUT employees.last_name%TYPE,
p_salary OUT employees.salary%TYPE,
p_comm OUT employees.commission_pct%TYPE)
AUTHID CURRENT_USER
IS
BEGIN
SELECT last_name, salary,
commission_pct
INTO p_name, p_salary, p_comm
FROM employees
WHERE employee_id=p_id;
END query_employee;
/
AUTHID DEFINER (Default option)
Invoker’s-Rights
To ensure that the procedure executes using the security of the executing
user, and not the owner,
use AUTHID CURRENT_USER. This ensures that the procedure executes
with the privileges and
schema context of its current user ie invoker .
Default behavior, as shown on the previous page, is when the procedure
executes under the security
domain of the owner; but if you wanted to explicitly state that the
procedure should execute using
the owner's privileges, then use AUTHID DEFINER.
Note:- AUTHID is introduced in Oracle8i. In previous versions of the Oracle
server, the behavior was based
on definer’s rights as described on the previous page.
List All Procedures and Functions
SELECT object_name, object_type
FROM user_objects
WHERE object_type in ('PROCEDURE','FUNCTION')
ORDER BY object_name;
List the Code of Procedures and Functions
SELECT text
FROM user_source
WHERE name = 'QUERY_EMPLOYEE'
ORDER BY line;
CREATE OR REPLACE PROCEDURE log_execution
IS
BEGIN
INSERT INTO log_table (user_id, log_date)
-- wrong
VALUES (USER, SYSDATE);
END;
/
Example
Given the above code for LOG_EXECUTION, there will be a compile error
when you run the
script for compilation.
List Compilation Errors by Using
USER_ERRORS
SELECT line || '/' || position POS, text
FROM user_errors
WHERE name = 'LOG_EXECUTION'
ORDER BY line;
SHOW ERRORS
PACKAGES
• Collection of related procedures and functions
• Make a call to any one of them. (proc/ Func.)and the entire
package(ALL PROGRAM UNITS IN THE PACKAGE) comes in to
the server RAM.
• Execution will be very fast (as in RAM).
• The entire package will remain in the server RAM till you end
your session. Even if you are not using it.
• When RAM gets full then internally LRU makes the RAM
free.Least recently used is removed.
• Package is stored in compiled format.
Package definition/specification:
Create or replace package delemp
as
Procedure del_emp (mdeptno number);
End;
Package body:-
SQL> Create or replace package body delemp
As
Function count_emp(mdeptno number)
return number
is
X number (4);
Begin
Select count(*) into x from emp
where deptno=mdeptno;
Return x;
End;
Procedure del_emp(mdeptno number)
is
X number(4);
begin
X := count_emp(mdeptno);
if X >0 then
delete from emp where deptno= mdeptno;
end if ;
end;
End ;
The package body consists of from “ begin to end” .
OUTPUT: Package created.
To execute:
SQL> execute package name .proc name
SQL> execute delemp.del_emp(10)
• Procedure first call’s function and check whether a dept. has
an employee. Now a procedure call’s other procedure or function if
they are at hard disk then slow.But if in a package then they are
both
in RAM.
In PLSQL , we have :
1. Declare
=======
Begin
========
delemp.delete_emp(10);
========
end;
To call function independently :
Select delemp.count_emp(10) from dual;
Declare
Y number (4);
Begin
Y: = delemp.count_emp(10);
Insert into tempp123
values (Y,’employee’);
End;
• The data ( program units & variables) present in package definition
is globally available.
(USED TO CREATE GLOBAL VARIABLES )
• The data present in package body is locally available
Forward Declaration:-
Create or replace package pg1
as
Procedure pt1(x number);
End;
Create or replace package body pg1
As
Procedure pr2; -- forward declaration
Procedure pt1(x number)
Is
Begin
Dbms_output.put_line(‘Pt1’);
Pr2;
End;
Procedure pr2
Is
Begin
Dbms_output.put_line(‘Pr2’);
End;
End;
Exec pg1.pt1(10);
Exec pg1.pr2; ----private procedure
6. SQL> Create or replace package pabc
As
Procedure one;
Procedure two;
End;
Create or replace package body pabc
As
Procedure one
Is
X number (4) :=1; /* Here X is a local variable*/
Begin
Insert into tempp123
Values (X,’A’);
X := X+1;
end;
Procedure two
is
X number (4) := 2;
Begin
Insert into tempp123
Values (X,’B’);
X: = X+1;
End;
End;
SQL> execute pabc.one
SQL> execute pabc.two
SQL> execute pabc.one
Execute Pabc.two is faster than execute Pabc.one because it is in RAM.
OUTPUT:
1 A
2 B
1 A
7. SQL> Create or replace package pgabc
as
Procedure one;
Procedure two;
end;
Create or replace package body pgabc
as
X number (4) := 0;
Procedure one
is
begin
X:= X+1;
Insert into tempp123
Values (X,’A’);
end;
Procedure two
is
begin
X := X+1;
Insert into tempp123
values (X,’B’);
Exception when others then
Dbms_output.put_line(‘hello’);
end;
end;
SQL> execute pgabc.one
SQL> execute pgabc.two
SQL> execute pgabc.one
OUTPUT :
1 A
2 B
3 A
• In the above program X is a global variable declared above the
procedure. Now global X remains in the server RAM. It becomes a
static variable.
• One can’t access variable X outside the package. To do so:
8. Create or replace package p_abc
as
X number(4):=0;
Procedure one;
Procedure Two;
end;
To access X :
9. Declare
Y number (4);
Begin
Y := p_abc.X + 1;
Insert into tempp123
values(Y,’Hello’);
p_abc.X:= p_abc.X + 1;
end;
• Ideally, always have all RELATED procedure & function in a package.
• The procedure and function in a package are normally called the
database triggers.
Procedure/Function Overloading in Packages:-
1. Overloading on basis of number of arguments.
Create or replace package p_overld
As
Procedure one(x number ,y number);
Procedure one (v varchar2);
end;
Create or replace package body p_overld
As
Procedure one(x number,y number)
is
begin
Insert into tempp123
Values (1,'proc_number');
End;
Procedure one (v varchar2)
Is
Begin
Insert into tempp123
Values (1,'proc_varchar');
End;
End;
Exec p_overld.one(‘a’);
Exec p_overld.one(1,2);
2. Overloading on basis of data type of arguments:-
Create or replace package p_overld
As
Procedure one(x number);
Procedure one(v varchar2);
end;
Create or replace package body p_overld
as
Procedure one(x number)
is
begin
insert into tempp123
Values(1,'proc_number');
end;
Procedure one(v varchar2)
is
begin
Insert into tempp123
Values (1,'proc_varchar');
End;
End;
Exec p_overld.one(‘a’);
Exec p_overld.one(1);
3. Overloading on basis of the order of arguments:-
Create or replace package p_overld
as
Procedure one(x number ,y varchar2);
Procedure one (v varchar2, m number);
end;
Create or replace package body p_overld
As
Procedure one(x number varchar2)
is
begin
Insert into tempp123
Values (1,'proc_number');
End;
Procedure one (v varchar2, m number)
Is
Begin
Insert into tempp123
Values (1,'proc_varchar');
End;
End;
Exec p_overld.one(1,‘a’);
Exec p_overld.one(‘a’,2);
PG1
P1 N1 N2 DEFAULT
P2 N1
Note:-
One proc (p1) in a package pg1 has two number parameters and the
second one is default parameter.
Second proc (p1) in a package pg1 has one number parameter.
Can they be overloaded.
Its gives a runtime error.( USING POSITIONAL METHOD)
Solution :
Overloading using named Method:-
Create or replace package pg12
As
Procedure p123(x number);
Procedure p123 (n number);
End;
Create or replace package body pg12
As
Procedure p123(x number)
As
Begin
dbms_output.put_line (‘x’);
End;
Procedure p123 (n number)
As
Begin
dbms_output.put_line (‘n’);
End;
End;
exec pg12.p123(x=>1);
exec pg12.p123(n=>2);
Advantages of Packages:-
1. Improved Performance.
2. Overloading.
3.GLOBAL VARIABLES
create or replace function f1
(x number)
return number
as
begin
dbms_output.put_line('f1');
return 1;
end;
/
declare
x number;
begin
x:=f1(x=>5); ---CAN be used when we are not sure abt the order of
arguments
end;
/
Database Triggers
Database Triggers :
• The procedures and functions in package are frequently called through
database triggers.
• Database triggers are present from OV7 onwards.
• It is a routine (set of commands) that gets executed automatically when
some events occur.
• Difference between procedure and trigger is that procedure needs to be
called while trigger is called automatically.
• Number of events that take place are :
Before insert -ST1 & RT1
After insert-ST2 & RT2
Before delete
After delete
Before update
After update
Database (DML) triggers are of 2 types:
a. Statement level trigger Fires once for every DML statement.
b. Row level trigger Fires once for each and every row, in the DML
statement.
DML STATEMENT:
Update emp
Set sal =sal + 100
Where deptno =10;
---3ROWS UPDATED.
ST1:ONCE
RT1:THRICE
As there are 6 events and 2 types a max of 12 triggers are possible on a
given table.
Statement level Trigger:-.
SQL> create or replace trigger t1
before insert
on emp
Begin
Insert into tempp123
Values (1,’inserted’);
end;
insert into emp(empno,sal) values(23,22222);
• Ideally there is a procedure which inserts into tempp123 faster than
other routines.
• In a trigger all PL SQL statements (except rollback & commit).
SQL> create or replace trigger abc
Before insert
on emp
Begin
Insert into tempp123
Values (1,’inserted’);
Commit;
end;
insert into emp(empno,sal) values(213,22222);
SQL> Rollback;
Now temp data commited but the insert in emp is roll backed
This leads to inconsistency of data.
Compare the difference between Statement level trigger and Row level
trigger:
Create or replace trigger t4 -----row level trigger
before update
on emp for each row
begin
insert into tempp123
values (1,’row level updated’);
end;
Create or replace trigger t5
before update
on emp
begin
Insert into tempp123
values (1,’statement level updated’);
End;
Update emp
Set sal=sal+100
Where deptno=10;
Row level insert:-
create or replace trigger abc
Before insert on emp
for each row
Begin
Insert into tempp123
Values (1,'inserted');
end;
insert into emp select * from copy_emp;
Bind variables in Triggers:-
SQL> create or replace trigger T6
Before insert
On emp
Begin
Insert into tempp123
Values (:new.sal, :new.fname);
end;
Insert into emp(empno,fname,sal,deptno) values(1,'xyx',3000,10);
• This can be used to create two copies of emp ie. One can maintain
multiple copies of a table during insert . This concept is called DATA
MIRRORING. Such as tempp123 table acts as a shadow table
• One can’t pass parameter to a trigger. But “:new.sal” these are global
variables . (Bind variables)
• “:new” can be used only in DB triggers(only Row level).
Create table deptot
(deptno number,
saltot number);
insert into deptot values(10,0);
insert into deptot values(20,0);
insert into deptot values(30,0);
SQL> create or replace trigger T7
before insert
on emp for each row
Begin
Update deptot set saltot = saltot + :new.sal
where deptno = :new.deptno;
end;
Insert into emp(empno,fname,sal,deptno) values(8,’deepak’,5600,10);
Database triggers for delete :
Create or replace trigger T8
before delete
on emp for each row
begin
insert into tempp123
values (1,’deleted’);
end;
Create or replace trigger T9
before delete
on emp
begin
insert into tempp123
values (1,’ st level deleted’);
end;
Create or replace trigger t9
Before delete
On emp for each row
Begin
Insert into tempp123
Values (:old.sal, :old.fname);
End;
:old delete
:new insert
:old + :new - update
Delete emp where deptno =10;
• For every row of dept the old value is stored in tempp123.This is
similar to Recycle Bin.
• Stores old values in the case of delete .Now tempp123 table called as
History Table.
• “ :old “ can be used with row level DB triggers . Read only global
bind variables.
Note:-
Insert :new
Delete :old
Update :new and :old both.
SQL> create or replace trigger T10
before delete
on emp for each row
begin
update deptot set saltot = saltot - :old.sal
where deptno = :old.deptno;
end;
Database triggers for update :
1. SQL> create or replace trigger T11
before update
on emp for each row
begin
insert into tempp123
values (:old.sal, :old.fname);
insert into tempp123
values (:new.sal, :new.fname);
end;
That is both (:old, :new) can be used for update. Thus , both history table
and shadow table maintained in case of update.
2. SQL> update emp
set sal = sal+100
where deptno=20 ;
create or replace trigger T12
before update
on emp for each row
begin
update deptot set saltot = saltot - :old.sal + :new.sal
where deptno = :old.deptno;
end;
/
3. SQL> update emp
set job=’Clerk’
Where empno= 1;
Now sal is not accessed in the emp table even then triggerT12 is invoked.
This will not affect the data but unnecessary processing will take place.
To avoid this unnecessary processing:
4. SQL> create or replace trigger T13
before update of sal
on emp for each row
begin
update deptot set saltot = saltot - :old.sal + :new.sal
where deptno = :old.deptno;
end;
• Now the triggers fires only when sal is updated
• This is only in case of update that we can be specific.
5. SQL> update emp
set sal=27000
Where empno= 1;
6. SQL> create or replace trigger T14
before update of sal, deptno
on emp for each row
begin
if updating ('deptno') then
Update deptot
set saltot = saltot - :old.sal
Where deptno = :old.deptno;
Update deptot
Set saltot =saltot +:new.sal
Where deptno= :new.deptno;
else
Update deptot
set saltot = saltot + :new.sal - :old.sal
where deptno = :old.deptno;
end if;
end;
UPDATE EMP
SET DEPTNO=30
Where deptno =10;
update emp
set sal =20000
where empno=1
This will fire only if deptno, sal are updated.
• Updating() = it is a function which is used only with DB triggers.
Returns a Boolean value.
Now again trigger fires unnecessary processing is done. To avoid this
we‘ve
Note:- the above trigger fires even when salary is not changed.
To avoid that:
8. SQL> create or replace trigger xyz
before update of sal, deptno
on emp for each row
when (old.sal <> new.sal or old.deptno <> new.deptno)
begin
if updating (‘deptno’) then
Update deptot
Set saltot = saltot - :old.sal
where deptno = :old.deptno;
Update deptot
Set saltot = saltot + :new.sal
where deptno = :new.deptno;
else
update deptot
set saltot = saltot + :new.sal - :old.sal
where deptno = :old.deptno;
end if;
end;
In the above SQL trigger, we do not use “ ; “ before begin statement.
The old tablename is destroyed when it enters in the begin block and then
drop.
9. SQL> create or replace trigger xyz
Before insert or delete or update of sal, deptno
on emp for each row
Begin
if inserting then
insert into tempp123 values(1,’inserting’);
elsif deleting then
Raise_application_error (-20001, ‘deletion not allowed’);
elsif updating(‘deptno’) then
insert into tempp123 values(1,’updating’);
end if;
end;
Insert into emp(empno,fname,sal,deptno) values(8,’deepak’,5600,10);
• Everything within one trigger is possible .
Therfore 12 triggers down to 4 triggers.
Triggers can also contain exceptions :
Create or replace trigger t5
before update
on emp
begin
Insert into tempp123
values (1,’statement level updated’);
exception when others then
null;
End;
Update emp
Set sal=sal+100
Where deptno=10;
11.SQL> delete from emp;
output:
ORA_20001 deletion not allowed
This can be possible to preserve security.
• Trigger can be used for validations. Security can be maintained
using grant and revoke.
• Conditional security can be enforced through trigger. For eg: if day is
Sunday then deletion is not possible.
12. SQL> drop trigger abc;
• When table is dropped all triggers dropped automatically.
• On delete cascade is internally a trigger.
13. SQL> alter trigger xyz disable;
14. SQL> alter trigger xyz enable;
Mutating tables :
If in a Trigger, we try to access the same row which we are updating ,we get
mutating table error.
Create or replace trigger abc
Before insert or update of sal on emp
For each row
Declare
v_minsal number;
v_maxsal number;
Begin
select min(sal),max(sal) into v_minsal,v_maxsal from emp
where deptno=:new.deptno;
End;
Update emp
Set sal=sal+100
Where deptno=20;
1 20
2 20
Hierarchy of execution (******)
1. Before insert statement level trigger.
2. Before insert row level trigger.
3. After insert row level
4. After insert statement level
Advanced Trigger Concepts
Creating Triggers on DDL Statements
CREATE [OR REPLACE] TRIGGER trigger_name
timing
[ddl_event1 [OR ddl_event2 OR ...]]
ON {DATABASE|SCHEMA}
trigger_body
Create or replace trigger st1_sch
before create
on schema
Begin
Insert into tempp123 values (1,’create trigger’);
End;
Conn system/excellent
Create or replace trigger st1_db
before Create
on database
begin
Insert into tabc values(1,’create trigger’);
end;
When you specify ON SCHEMA, the trigger fires for the specific user.
If you specify ON DATABASE, the trigger fires for all users.
DDL triggers fire only if the object being created is a cluster, function,
index, package, procedure, role, sequence, synonym, table, tablespace,
trigger, type, view, or user.
LOGON and LOGOFF Trigger Example:-
Create or replace trigger logon_trig
after logon on schema
begin
Insert into tempp123 values (1,’log on’);
end;
/
Create or replace trigger logoff_trig
before logoff on schema
begin
insert into tempp123 values(1, ‘log off’);
end;
/
CALL Statements in a trigger
Create or replace trigger log_employee
before insert on emp
call p1
/
Insert into emp(empno,fname,sal,deptno) values(8,’deepak’,5600,10);
Note: There is no semicolon at the end of the CALL statement.
Implementing Triggers
You can use trigger for:
• Security
• Auditing
• Data integrity
• Referential integrity
• Computing derived data automatically
1. Security
Create or replace trigger secure_emp
before insert or update or delete on emp
Declare
v_dummy varchar2(1);
begin
if (to_char (sysdate, 'dy') in ('sat','wed',’thu’))then
raise_application_error (-20506,'deletion not allowed on sat.');
end if;
end;
/
Delete emp;
2. Auditing by Using a Trigger
• Write the audit trail to a user-defined audit table
3. Enforcing Data Integrity
Create or replace trigger check_salary
before update of sal on emp
for each row
when (new.sal < old.sal)
begin
raise_application_error (-20508, 'cannot decrease salary.');
end;
/
4. Enforcing Referential Integrity
Create or replace trigger cascade_updates
after update of deptno on dept
for each row
declare
x number;
begin
update emp
set emp.deptno=:new.deptno
where emp.deptno=:old.deptno;
end;
/
update dept set deptno=20 where deptno=30;
possible only when u have no fk constraints between emp and dept
If FK constraints are present then update will fail.
5. Computing Derived Data
alter table dept
add total_sal number;
Update dept
set total_sal=(select sum(sal)
from emp
where emp.deptno =dept.deptno);
Create or replace procedure increment_salary
(p_id in dept.deptno%type,
p_salary in dept.total_sal%type)
is
begin
Update dept
set total_sal = nvl (total_sal, 0)+ p_salary
where deptno = p_id;
End increment_salary;
Create or replace trigger compute_salary
after insert or update of sal or delete on emp
for each row
Begin
if deleting then
increment_salary (:old.deptno,(-1*:old.sal));
elsif updating then
increment_salary(:new.deptno,(:new.sal-:old.sal));
else increment_salary(:new.deptno,:new.sal); --insert
end if;
end;
Insert into emp(empno,sal,deptno) values (11,8000,10);
update emp set sal =10000 where empno=2 and deptno =10;
delete emp where empno=2 and deptno=10;
PL/SQL Tables(Arrays)
Create table emp_test
(empno number,ename varchar2(30));
Example 1:-
Declare
TYPE emp_plsqltab1 IS TABLE OF char(30) INDEX BY BINARY_INTEGER;
e emp_plsqltab1;
i binary_integer:=1;
ioCursor c1 is
Select empno, fname from emp;
Begin
for x in c1
loop
e(i):=x.fname;
insert into emp_test values(1,e(i));
i:=i+1;
end loop;
end;
Example 2:-
Declare
Type emp_rec is record (empno number, ename varchar2 (30) );
TYPE emp_plsqltab IS TABLE OF emp_rec INDEX BY BINARY_INTEGER;
e emp_plsqltab;
i binary_integer:=1;
Cursor c1 is
Select empno, fname from EMP;
Begin
For x in c1
Loop
e(i).empno:=x.empno;
e(i).ename:=x.fname;
Insert into emp_test values(e(i).empno,e(i).ename);
i:=i+1;
end loop;
end;
Note: Binary integar is used to store integers.
Range is 2 billion.
REF Cursor
A Cursor is a memory area; a Ref Cursor is a pointer to that.
A ref cursor can be passed a parameter to a procedure.
A ref cursor is used to return a set of records from the procedure to the
front end. (Note a normal cursor cannot be used).
The select statement of a ref cursor can be modified dynamically.
Create or replace package emp_data
as
type empcurtyp is ref cursor return emp%rowtype;
Procedure open_emp_cv (emp_cv in out empcurtyp,ch number);
end;
/
Create or replace package body emp_data
as
Procedure open_emp_cv (emp_cv in out empcurtyp,ch number) is
begin
if (ch=1) then
open emp_cv for select * from emp where deptno=10;
elsif (ch=2) then
open emp_cv for select * from emp where deptno=20;
end if;
end open_emp_cv;
End emp_data;
/
Create or replace procedure b1(p_choice in number)
is
empcurtyp1 emp_data.empcurtyp;--cursor variable like emp_cv
e emp%rowtype;
begin
emp_data.open_emp_cv(empcurtyp1,p_choice);
loop
fetch empcurtyp1 into e;
exit when empcurtyp1%notfound;
dbms_output.put_line (e.empno);
dbms_output.put_line (e.fname);
end loop;
End;
/
Dynamic SQL
Dynamic SQL:
• Is a SQL statement that contains variables that can
change during runtime.
• Enables general-purpose code to be written. Generic code.
SQL statements go through various stages:
Parse
Every SQL statement must be parsed. Parsing the statement includes
checking the statement's syntax and validating the statement, ensuring
that all references to objects are correct, and ensuring that the relevant
privileges to those objects exist.
Bind
After parsing, the Oracle server knows the meaning of the Oracle statement
but still may not have enough information to execute the statement. The
Oracle server may need values for any bind variable in the statement. The
process of obtaining these values is called binding variables.
Compile & Execute
At this point, the Oracle server has all necessary information and
resources, and the statement is executed.
Fetch
In the fetch stage, rows are selected(ie cursor is formed and returned)
and ordered (if requested by the query).
DBMS_SQL Package
The DBMS_SQL package is used to write dynamic SQL
in stored procedures and functions.
1. Use OPEN_CURSOR to establish an area in memory to process a SQL
statement.
2. Use PARSE to establish the validity of the SQL statement.
3. Use the EXECUTE function to run the SQL statement. This function
returns the number of row processed.
4. Use CLOSE_CURSOR to close the cursor.(free up the memory)
CREATE OR REPLACE PROCEDURE delete_all_rows
(p_tab_name IN VARCHAR2, p_rows_del OUT NUMBER)
IS
Cursor_name INTEGER;
BEGIN
cursor_name := DBMS_SQL.OPEN_CURSOR;
DBMS_SQL.PARSE(cursor_name, 'DELETE FROM '||p_tab_name,
DBMS_SQL.NATIVE );
p_rows_del := DBMS_SQL.EXECUTE (cursor_name);
DBMS_SQL.CLOSE_CURSOR(cursor_name);
END;
/
VARIABLE deleted NUMBER
EXECUTE delete_all_rows('emp', :deleted)
EXECUTE IMMEDIATE Statement
Dynamic SQL Using EXECUTE IMMEDIATE
CREATE OR REPLACE PROCEDURE del_rows
(p_table_name IN VARCHAR2,
p_rows_deld OUT NUMBER)
IS
BEGIN
EXECUTE IMMEDIATE 'delete from '||p_table_name;
p_rows_deld := SQL%ROWCOUNT;
END;
/
VARIABLE deleted NUMBER
EXECUTE del_rows('tempp’,:deleted)
PRINT deleted
Exec immediate can be used to perform ddl in procedures,func,packages:
CREATE OR REPLACE PROCEDURE dsql_ddl
IS
BEGIN
EXECUTE IMMEDIATE 'create table cvv (col2 number)’;
END;