Professional Documents
Culture Documents
PL/SQL
Procedural Language Extension to SQL
Today’s Topics
Error Handling
Stored Procedures
Procedure
Function
Package
PL/SQL - Introduction
Procedural extension allowing for modularity, variable
declaration, loops and logical constructs.
PL/SQL Engine
PL/SQL Engine
Procedural
PL/SQL block PL/SQL block Procedural Statement Statement
Executor
SQL
SQL
Statement
Executor
Oracle Server
IGSI Confidential | Wednesday, August 5, 2009 © Copyright IBM Corporation 2003
IBM Global Services
PL/SQL Structure
IF Constructor
CASE Statement
CASE grade
WHEN ’A’ THEN dbms_output.put_line(’Excellent’);
WHEN ’B’ THEN dbms_output.put_line(’Very Good’);
WHEN ’C’ THEN dbms_output.put_line(’Good’);
WHEN ’D’ THEN dbms_output.put_line(’Fair’);
WHEN ’F’ THEN dbms_output.put_line(’Poor’);
ELSE dbms_output.put_line(’No such grade’);
END CASE;
FOR Loop
WHILE Loops
DECLARE
TEN number:=10;
i number_table.num%TYPE:=1;
BEGIN
WHILE i <= TEN LOOP
INSERT INTO number_table
VALUES(i);
i := i + 1;
END LOOP;
END;
GOTO Statement
Types of Cursors
Implicit Cursors
Get created automatically every time you use an INSERT,
UPDATE, DELETE or SELECT command
Doesn’t need to be declared.
Symbolic Name is SQL
Explicit Cursors
Needs to be explicitly created
Symbolic Name is user-given.
Used if query returns more than one record.
Implementation of %rowcount
SQL> begin
2 update emp1
3 set sal = sal + 500
4 where empno=&emp_no;
5 if sql%rowcount = 1 then
6 dbms_output.put_line('Employee Successfully Updated');
7 end if;
8 end;
9 /
Enter value for emp_no: 8003
old 4: where empno=&emp_no;
new 4: where empno=8003;
Employee Successfully Updated
Another Implementation
1 declare
2 vsal number;
3 begin
4 select sal into vsal
5 from emp1
6 where empno=&emp_no;
7 if sql%found then
8 dbms_output.put_line('Employee Successfully Found');
9 else
10 dbms_output.put_line('Employee Not Successfully Found');
11 end if;
12 exception
13 when no_data_found then
14 dbms_output.put_line('Employee Not Found');
15* end;
16 /
Enter value for emp_no: 8009
old 6: where empno=&emp_no;
new 6: where empno=8009;
Employee Not Found
Declaring Cursor
Declaring a cursor defines the name of the cursor and
associates it with a SELECT statement.
Syntax:
e.g.
Cursor c_myCursor is
Select emp.name, emp.dept
from employee
where salary > 5000;
Opening a Cursor
When the Open cursor statement is processed, the following
four actions will take place automatically:
1. The variables (including bind variables) in the WHERE
clause are examined.
2. Based on the values of the variables, the active set is
determined and the PL/SQL engine executes the query for
that cursor. Variables are examined at cursor open time
only.
3. The PL/SQL engine identifies the active set of data—the
rows from all involved tables that meet the WHERE clause
criteria.
4. The active set pointer is set to the first row.
Fetching Records
After the cursor has been declared and opened, you can
then retrieve data from the cursor. The process of getting
the data from the cursor is referred to as fetching the
cursor. There are two methods of fetching a cursor, done
with the following command:
Closing Cursor
Once all of the rows in the cursor have been
processed (retrieved), the cursor should be closed.
This tells the PL/SQL engine that the program is
finished with the cursor, and the resources
associated with it can be freed.
The syntax for closing the cursor is
CLOSE cursor_name;
An Example
declare
cursor c_emp_cursor IS Select * from employee;
BEGIN
FOR myrow IN c_emp_cursor --NO OPEN
LOOP
dbms_output.put_line(myrow.Emp_Name || ' ' ||
myrow.Salary); --NO FETCH
end loop; --NO CLOSE
DECLARE
bonus REAL;
BEGIN
FOR emp_rec IN (SELECT empno, sal, comm FROM emp) LOOP
bonus := (emp_rec.sal * 0.05) + (emp_rec.comm * 0.25);
INSERT INTO bonuses VALUES (emp_rec.empno, bonus);
END LOOP;
COMMIT;
END;
total_wages NUMBER(11,2) := 0;
high_paid NUMBER(4) := 0;
higher_comm NUMBER(4) := 0;
BEGIN
/* the number of iterations will equal the number of rows * * returned by emp_cursor */
DECLARE
CURSOR csr_1 IS
SELECT * FROM sec_hrc_tab FOR UPDATE OF hrc_descr;
BEGIN
/* . . . Open the cursor and process the resultset . . . */
END;
Once you’ve defined a SELECT FOR UPDATE cursor, you use the
WHERE CURRENT OF clause to process the rows returned by it. You
can use this clause in an UPDATE or DELETE statement.
DECLARE
CURSOR csr_1 IS
SELECT * FROM sec_hrc_tab FOR UPDATE OF hrc_descr;
v_hrc_descr VARCHAR2(20);
BEGIN
FOR idx IN csr_1 LOOP
v_hrc_descr := UPPER(idx.hrc_descr);
UPDATE sec_hrc_tab
SET hrc_descr = v_hrc_descr
WHERE CURRENT OF csr_1;
END LOOP;
COMMIT;
END;
Cursor Variables
An explicit cursor once declared is associated with a specific query—only the
one specific query that was known at compile time. In this way, the cursor
declared was static and couldn’t be changed at runtime.
A cursor variable is a single PL/SQL variable that you can associate with
different queries at runtime.
A Complete Example
DECLARE
TYPE rc is REF CURSOR;
v_rc rc;
hrc_rec hrc_tab%ROWTYPE;
BEGIN
OPEN v_rc FOR SELECT * from hrc_tab;
dbms_output.put_line(‘Hierarchy Details’);
dbms_output.put_line(‘------------------------’);
dbms_output.put_line(‘Code’||’ ‘||rpad(‘Description’,20,’ ‘));
dbms_output.put_line(rpad(‘-’,4,’-’)||’ ‘||rpad(‘-’,20,’-’));
LOOP
FETCH v_rc INTO hrc_rec;
EXIT WHEN v_rc%NOTFOUND;
dbms_output.put_line(to_char(hrc_rec.hrc_code)||’ ‘||
rpad(hrc_rec.hrc_descr,20,’ ‘));
END LOOP;
CLOSE v_rc;
END;
The Ref Cursor variable which doesn’t dictate the return type of the cursor is a
WEAK Ref Cursor Type. For eg
TYPE rc IS REF CURSOR;
v_rc rc;
Hence, it can point to any SELECT query with any number of columns.
DECLARE
TYPE tcursor IS REF CURSOR;
tcur tcursor;
e1 emp%ROWTYPE;
d1 dept%ROWTYPE;
tname VARCHAR2(20);
BEGIN
tname := &tablename;
IF tname = 'emp' THEN
OPEN tcur FOR SELECT * FORM emp;
DBMS_OUTPUT.PUT_LINE ('Emp table opened.');
close tcur;
DBMS_OUTPUT.PUT_LINE ('Emp table closed.');
ELSE IF tname = 'dept' THEN
OPEN tcur FOR SELECT * FROM dept;
DBMS_OUTPUT.PUT_LINE ('Dept table opened.');
close tcur;
DBMS_OUTPUT.PUT_LINE ('Emp table closed.');
ELSE
RAISE_APPLICATION_ERROR (-20004, 'Table name is wrong');
END IF;
END;
DECLARE
TYPE ecursor IS REF CURSOR RETURN emp%ROWTYPE;
ecur ecursor;
e_rec emp%ROWTYPE;
dn NUMBER;
BEGIN
dn := &deptno;
OPEN ecur FOR SELECT * FROM emp WHERE deptno = dn;
Creating Procedures
Oracle
Procedure
Builder Edit Text
file
System 1
editor Store in
database
Source 2
code
Compile
parsed-code
Execute
IGSI Confidential | Wednesday, August 5, 2009 © Copyright IBM Corporation 2003
IBM Global Services
1. From SQL*Plus, run the script file to compile the source code
into parsed-code and store both in the database.
DECLARE
v_id NUMBER := 7900;
BEGIN
raise_salary(v_id); --invoke procedure
COMMIT;
...
END;
Procedure
IN parameter
Calling
environment OUT parameter
IN OUT parameter
(DECLARE)
BEGIN
EXCEPTION
END;
IN Parameters: Example
7369 v_id
7654 v_id
MARTIN v_name
1250 v_salary
1400 v_ comm
IN OUT Parameters
Calling environment
'(800)633-0575' '(800)633-0575'
G_PHONE_NO
---------------
(800)633-0575
Positional
Named
Combination
SQL> begin
2 add_dept;
3 add_dept ( 'TRAINING', 'NEW YORK');
4 add_dept ( v_loc => 'DALLAS', v_name =>
'EDUCATION') ;
5 add_dept ( v_loc => 'BOSTON') ;
6 end;
7 /
PL/SQL procedure successfully completed.
Using SQL*Plus:
-Syntax
-Example
Creating Functions
Creating a Function
Oracle
Procedure
Builder Edit Text
file
System 1
editor Store in
database
Source 2
code
Compile
p-code
Execute
Executing Functions
7934 v_id
Using SQL*Plus
- Syntax
- Example
Procedure Function
Improved performance
Improved maintenance
Improved data security and integrity
Creating Packages
Advantages of Packages
Modularity
Easier application design
Information hiding
Added functionality
Better performance
Overloading
Developing a Package
1
Package Procedure A
specification declaration 2
4
Procedure B
definition 3
Package
body
Procedure A
definition 2
5
Package G_COMM 1
specification RESET_COMM 2
procedure declaration
VALIDATE_COMM
function definition 3
Package
body
RESET_COMM
procedure definition 2
Overloading
Overloading : Example
Initialize the first 50 rows in two PL/SQL tables.
Removing Packages
Exception Handling
In PL/SQL a warning or error condition is called an exception. Exceptions can
be internally defined (by the runtime system) or user-defined.
Run-time errors arise from design faults, coding mistakes, hardware failures,
and many other sources. Although you cannot anticipate all possible errors, you
can plan to handle certain kinds of errors meaningful to your PL/SQL program.
With PL/SQL, a mechanism called exception handling lets you "bulletproof"
your program so that it can continue operating in the presence of errors.
When an error occurs, an exception is raised. That is, normal execution stops
and control transfers to the exception handling part of your PL/SQL block or
subprogram. Internal exceptions are raised implicitly (automatically) by the
runtime system. User-defined exceptions must be raised explicitly by RAISE
statements, which can also raise predefined exceptions.
To handle raised exceptions, you write separate routines called exception
handlers. After an exception handler runs, the current block stops executing
and the enclosing block resumes with the next statement. If there is no
enclosing block, control returns to the host environment.
Pre-defined Exception
An internal exception is raised implicitly whenever your PL/SQL program
violates an Oracle rule or exceeds a system-dependent limit. Every Oracle error
has a number, but exceptions must be handled by name. For example, the
predefined exception NO_DATA_FOUND is raised if a SELECT INTO
statement returns no rows.
The table below lists some of these exceptions with their names and a short
description.
User-defined Exceptions
Raising an Exception
DECLARE DECLARE
out_of_stock EXCEPTION; acct_type INTEGER := 7;
number_on_hand NUMBER(4); BEGIN
BEGIN IF acct_type NOT IN (1, 2, 3) THEN
... -- raise predefined exception
IF number_on_hand < 1 THEN RAISE INVALID_NUMBER;
RAISE out_of_stock; END IF;
END IF; EXCEPTION
EXCEPTION WHEN INVALID_NUMBER THEN
WHEN out_of_stock THEN ROLLBACK;
-- handle the error END;
END;
DECLARE
e_emps_remaining EXCEPTION;
e_emps_remaining EXCEPTION;
PRAGMA
PRAGMA EXCEPTION_INIT
EXCEPTION_INIT (( 1
e_emps_remaining,
e_emps_remaining,-2292);
-2292);
v_deptno dept.deptno%TYPE := &p_deptno; 2
BEGIN
DELETE FROM dept
WHERE deptno = v_deptno;
COMMIT;
EXCEPTION
WHEN e_emps_remaining
e_emps_remaining THEN
DBMS_OUTPUT.PUT_LINE ('Cannot remove dept ' || 3
TO_CHAR(v_deptno) || '. Employees exist. ');
END;
SQLCODE
Returns the numeric value for the error code
SQLERRM
Returns the message associated with the error number
Example
DECLARE
v_error_code NUMBER;
v_error_message VARCHAR2(255);
BEGIN
...
EXCEPTION
...
WHEN OTHERS THEN
ROLLBACK;
v_error_code := SQLCODE ;
v_error_message := SQLERRM
SQLERRM ;
INSERT INTO errors VALUES(v_error_code,
v_error_message);
END;
RAISE_APPLICATION_ERROR Procedure
Syntax
raise_application_error (error_number,
message[, {TRUE | FALSE}]);
Example
1 Declare
2 curr_sal NUMBER;
3 vempno NUMBER := &emp_id;
4 BEGIN
5 SELECT sal INTO curr_sal FROM emp WHERE empno = vempno ;
6 IF curr_sal IS NULL THEN
7 raise_application_error(-20101, 'Salary is missing');
8 ELSE
9 UPDATE emp SET sal = curr_sal + 500
10 WHERE empno = vempno ;
11 END IF;
12* END;
SQL> /
Enter value for emp_id: 7900
old 3: vempno NUMBER := &emp_id;
new 3: vempno NUMBER := 7900;
Declare
*
ERROR at line 1:
ORA-20101: Salary is missing
ORA-06512: at line 7
IGSI Confidential | Wednesday, August 5, 2009 © Copyright IBM Corporation 2003