Sie sind auf Seite 1von 51

PL/SQL is a procedural extension for Oracles Structured Query Language.

PL/SQL is not a separate


language rather a technology. Mean to say that you will not have a separate place or prompt for executing
your PL/SQL programs. PL/SQL technology is like an engine that executes PL/SQL blocks and
subprograms. This engine can be started in Oracle server or in application development tools such as
Oracle Forms, Oracle Reports etc.

As shown in the above figure PL/SQL engine executes procedural statements and sends SQL part of
statements to SQL statement processor in the Oracle server. PL/SQL combines the data manipulating power
of SQL with the data processing power of procedural languages.
Block Structure of PL/SQL: PL/SQL is a block-structured language. i.e. Programs of PL/SQL contain
logical blocks.

As shown in the Fig.2 a PL/SQL block has three parts.


1) Declaration:

Necessary

variables

are

declared

in

this

section.

(Optional)

2) Begin: This section contain executable statements of SQL and PL/SQL


3) Exception: Any error occurred while executing the statements in begin part can be handled in this
part.
1

Variables and Constants: Variables are used to store query results. Forward references are not allowed.
Hence you must first declare the variable and then use it.
Variables can have any SQL datatype, such as CHAR, DATE, NUMBER etc or any PL/SQL datatype like
BOOLEAN, BINARY_INTEGER etc.

Declaring Variables: Variables are declared in DECLARE section of PL/SQL.


declare
sno number (3);
sname varchar2 (15);
___
begin
Assigning values to variables:
SNO NUMBER : = 1001; or SNAME := JOHN; etc

Following screen shot explain you how to write a simple PL/SQL program and execute it.

SET SERVEROUTPUT ON is a command used to access results from Oracle Server.


A PL/SQL program is terminated by a / . DBMS_OUTPUT is a package and PUT_LINE is a procedure
in it. You will learn more about procedures, functions and packages in the following sections.
Above program can also be written as a text file in Notepad editor and then executed as explained in the
following screen shot.

Scope and Visibility of Variables: An identifier in PL/SQL block is considered as local to that block and
global to all its Sub-blocks. Which is better understood from the following example.

EXCEPTION HANDLING
Exceptions
An Exception is an error situation, which arises during program execution. When an error occurs exception
is raised, normal execution is stopped and control transfers to exception-handling part. Exception handlers
are routines written to handle the exception. The exceptions can be internally defined (system-defined or
pre-defined) or User-defined exception.
Predefined exception is raised automatically whenever there is a violation of Oracle coding rules.
Predefined exceptions are those like ZERO_DIVIDE, which is raised automatically when we try to divide a
number by zero. Other built-in exceptions are given below. You can handle unexpected Oracle errors using
OTHERS handler. It can handle all raised exceptions that are not handled by any other handler. It must
always be written as the last handler in exception block.

CURSOR_ALREADY_OPEN Raised when we try to open an already open cursor.

DUP_VAL_ON_INDEX When you try to insert a duplicate value into a unique column

INVALID_CURSOR It occurs when we try accessing an invalid cursor

INVALID_NUMBER On usage of something other than number in place of number value.

LOGIN_DENIED At the time when user login is denied

TOO_MANY_ROWS When a select query returns more than one row and the destination
variable can take only single value.

WHEN_NO_DATA_FOUND When a select/update/delete query returns no value

VALUE_ERROR When an arithmetic, value conversion, truncation, or constraint error occurs.

Predefined exception handlers are declared globally in package STANDARD. Hence we need not have to
define them rather just use them.
The biggest advantage of exception handling is it improves readability and reliability of the code. Errors
from many statements of code can be handles with a single handler. Instead of checking for an error at
every point we can just add an exception handler and if any exception is raised it is handled by that.
For checking errors at a specific spot it is always better to have those statements in a separate begin end
block.

Examples: Following example gives the usage of ZERO_DIVIDE exception

Example 2: I have explained the usage of NO_DATA_FOUND exception in the following

The DUP_VAL_ON_INDEX is raised when a SQL statement tries to create a duplicate value in a column
on which a primary key or unique constraints are defined.
6

Example to demonstrate the exception DUP_VAL_ON_INDEX.

More than one Exception can be written in a single handler as shown below.
EXCEPTION
When NO_DATA_FOUND or TOO_MANY_ROWS then
Statements;
END;

User-defined Exceptions : A User-defined exception has to be defined by the programmer. User-defined


exceptions are declared in the declaration section with their type as exception. They must be raised
explicitly using RAISE statement, unlike pre-defined exceptions that are raised implicitly. RAISE
statement can also be used to raise internal exceptions.
Declaring Exception:
DECLARE
myexception EXCEPTION;
BEGIN
-----Raising Exception:
BEGIN
RAISE myexception;

------Handling Exception:
BEGIN
-----EXCEPTION
WHEN myexception THEN
Statements;
END;

Points To Ponder:

An Exception cannot be declared twice in the same block.

Exceptions declared in a block are considered as local to that block and global to its sub-blocks.

An enclosing block cannot access Exceptions declared in its sub-block. Where as it possible for a
sub-block to refer its enclosing Exceptions.

The following example explains the usage of User-defined Exception

RAISE_APPLICATION_ERROR

To display your own error messages one can use the built-in RAISE_APPLICATION_ERROR. They
display the error message in the same way as Oracle errors. You should use a negative number between
20000 to 20999 for the error_number and the error message should not exceed 512 characters.
The syntax to call raise_application_error is
RAISE_APPLICATION_ERROR (error_number, error_message, { TRUE | FALSE });

Propagation of Exceptions
When an exception is raised and corresponding handler is not found in the current block then it propagates
to the enclosing blocks till a handler is found. If a handler is not found in its enclosing blocks also then it
raises an unhandled exception error to the host environment.
Exceptions cannot be propagated across remote procedure calls. i.e. a PL/SQL program cannot catch
exceptions raised by remote subprograms.
Reraising exceptions
When you want an exception to be handles in the current block as well in its enclosing block then you need
to use RAISE statement without an exception name.

10

PL/SQL TABLES
PL/SQL Tables: PL/SQL tables are modeled as database tables but are not same as database tables.
The size of a PL/SQL table is unconstrained i.e. it can grow dynamically whenever a new record is added.
Its size is constrained only by the available memory.
Every PL/SQL table will have a primary key column of BINARY_INTEGER type.

11

12

RECORDS
The %rowtype attribute can be used to store a record fetched from the table. But it is not possible to declare
datatype for the fields in %rowtype. This problem is solved in the object type RECORD. The usage of
%rowtype and RECORD object are explained below.

13

Index-By Table (Associate Arrays)


An index-by table (also called an associative array) is a set of key-value pairs. Each key is unique and is
used to locate the corresponding value. The key can be either an integer or a string.
An index-by table is created using the following syntax. Here, we are creating an index-by table
namedtable_name whose keys will be of subscript_type and associated values will be of element_type.
TYPE type_name IS TABLE OF element_type [NOT NULL] INDEX BY subscript_type;
table_name type_name;
============================================================================
DECLARE
TYPEEMP_SALISTABLEOFNUMBERINDEXBYVARCHAR2(20);
TYPEEMP_NAMEISTABLEOFVARCHAR2(20)INDEXBYPLS_INTEGER;

V1EMP_SAL;
V1_salVARCHAR2(20);
V2EMP_NAME;
BEGIN
V1('A'):=5000;
V1('B'):=2000;
V1('C'):=6000;
V1('D'):=8000;
V2(1):='KING';
V2(2):='JAMES';
V2(3):='NAZEER';
dbms_output.put_line(V1.FIRST);PrintsthefirstIndexvalueofV1i.e.,A
dbms_output.put_line(V1.NEXT('A'));PrintsthenextIndexvalueofV1i.e.,B
dbms_output.put_line(V1.LAST);PrintstheLASTindexvalueofV1i.e.,D
dbms_output.put_line(V1('A'));PrintsthevaluesassignedtoA

v1_sal:=v1.FIRST;
dbms_output.put_line(V1(V1_SAl));PrintsthevaluesoffirstindexV1('A')
v1_sal:=v1.NEXT(V1_SAL);
dbms_output.put_line(V1(V1_SAL));Printsthenextvaluei.e.,V1('B');
v1_sal:=v1.LAST;
dbms_output.put_line(V1(V1_SAL));Printsthelastvaluei.e.,V1('D');
dbms_output.put_line(V2(1));
PrintsthevalueKINGasitassignedtoV2(1)
dbms_output.put_line(V2(2));
PrintsthevalueJAMESasitassignedtoV2(2)
dbms_output.put_line(V2(3));
PrintsthevalueNZEERasitassignedtoV2(3)
dbms_output.put_line(v2.prior(3)); Printsthepriorindexvaluei.e.,indexnumber2inV2
dbms_output.put_line(v2(V2.prior(3)));PrintsthepreviousvalueJAMESprevioustoNAZEER
dbms_output.put_line(v2.NEXT(1));Printsthepreviousindexi.e.,indexnumber2inV2
dbms_output.put_line(v2(V2.NEXT(1)));PrintsthevalueNEXTvalueof1JAMES
dbms_output.put_line('BeforeDeleteTotalNumberofelementesinV2='||V2.count);
V2.DELETE(1);
V2.DELETE(3,8);Deletesfrom3to8(3,4,5,6,7,8)
dbms_output.put_line('AfterDeleteTotalNumberofelementesinV2='||V2.count
FORIINV2.FIRST..V2.LASTPrintsfromthe2ndrecordsasfirstisdeleted
LOOP
DBMS_OUTPUT.PUT_LINE(V2(I));
ENDLOOP;
END;

14

#2Showsupplierinformation
DECLARE
TYPESUPPLIER_LISTISTABLEOFAP_SUPPLIERS%ROWTYPEINDEXBYPLS_INTEGER;
S1SUPPLIER_LIST;
BEGIN
SELECT*BULKCOLLECTINTOS1FROMAP_SUPPLIERS;
FORIINS1.FIRST..S1.LAST
FORIIN1..10
LOOP
dbms_output.put_line(S1(I).vendor_id||''||s1(i).vendor_name||''||s1(i).segment1);
ENDLOOP;
END;

15

CONTROL STRUCTURES
The control structures of PL/SQL are simple yet powerful. Control structures in PL/SQL can be divided
into
selection
or
conditional,
iterative
and
sequential.
Conditional Control (Selection): This structure tests a condition, depending on the condition is true or
false it decides the sequence of statements to be executed.
Example IF-THEN, CASE and searched CASE statements.
Syntax for IF-THEN
IF THEN
Statements
END IF;
Example :

Syntax for IF-THEN-ELSE:


IF THEN
Statements
ELSE
statements

16

END IF;
Example: Check whether the given number is <5 or >5.

Example 2: Find the given number is even or odd


SQL> Ed even_odd.sql
declare
n number;
begin
dbms_output.put_line (enter a number );
n:=&number;
if mod(n,2)=0 then
dbms_output.put_line (entered number is even);
else
dbms_output.put_line (entered number is odd);
end if;
end;

17

IF-THEN-ELSIF:
IF THEN
Statements
ELSIF THEN
Statements
ELSE
Statements
END IF;

18

CASE..WHEN
The CASE statement chooses from a sequence of conditions, and executes a corresponding statement. The
CASE statement evaluates a single expression and compares it against several potential values, or evaluates
multiple Boolean expressions and chooses the first one that is TRUE.
The syntax for the case statement is:
CASE [ expression ]
WHEN condition_1 THEN result_1
WHEN condition_2 THEN result_2
...
WHEN condition_n THEN result_n
ELSE result
END
expression is optional. It is the value that you are comparing to the list of conditions. (ie: condition_1,
condition_2, ... condition_n)
condition_1 to condition_n must all be the same datatype. Conditions are evaluated in the order listed.
Once a condition is found to be true, the case statement will return the result and not evaluate the
conditions any further.
result_1 to result_n must all be the same datatype. This is the value returned once a condition is found to be
true.
Example:
Declare
in_dt date:=&in_dt;
v_out VARCHAR2(10);
begin
case to_char(in_dt,'d')
when 1 then
v_out:='SUNDAY';
when 7 then
v_out:='SATURDAY';
else
v_out:='WEEKDAY';
end case;
dbms_output.put_line (v_out);
end;
/

19

ITERATIVE CONTROL
(LOOPS)
LOOP statement executes the body statements multiple times. The statements are placed between LOOP
END LOOP keywords.
The simplest form of LOOP statement is an infinite loop. EXIT statement is used inside LOOP to terminate
it.
Syntax for LOOP- END LOOP
LOOP
Statements
END LOOP;
Example:
BEGIN
LOOP
DBMS_OUTPUT.PUT_LINE (Hello);
END LOOP;
END;

20

LABELING LOOPS
We can label Loops. A Label is undeclared identifier enclosed between double angle brackets( Ex. <>). The
following example demonstrates usage of labels in loops.

21

WHILE-LOOP
This is similar to LOOP. A condition placed between WHILE and LOOP is evaluated before each iteration.
If the condition evaluates to TRUE the statements are executed and the control resumes at the top of the
LOOP. If the condition evaluates to FALSE or NULL then control comes out of the loop.

FOR LOOP:
The FOR LOOP is used to repeatedly execute a set of statements for certain number of times specified by
a starting number and an ending number. The variable value starts at the starting value given and
increments by 1(default and can not be changed) with each iteration. The iteration stops when the variable
value reaches end value specified.
Syntax:
FOR IN
LOOP
Statements
END LOOP;

22

23

Sequential Control Statements


The GOTO statement is used for doing unconditional branching to a named label. Its frequent usage is not
recommended. We should have at least one executable statement following the label. GOTO statements can
some time result in complex, unstructured code making it difficult to understand.
Points To be remembered while working with GOTO:

A statement, at least NULL statement, must follow every GOTO statement

A GOTO statement can branch to enclosing block from the current block

A GOTO statement cannot branch from one IF statement clause to another.

A GOTO statement cannot branch from an enclosing block into a sub-block.

A GOTO statement cannot branch out of a subprogram.

A GOTO cannot branch from an exception handler to current block. But it can branch from the
exception handler to an enclosing block
24

CURSORS
Cursor : For every SQL statement execution certain area in memory is allocated. PL/SQL allow you to
name this area. This private SQL area is called context area or cursor. A cursor acts as a handle or pointer
into the context area. A PL/SQL program controls the context area using the cursor. Cursor represents a
structure in memory and is different from cursor variable.
When you declare a cursor, you get a pointer variable, which does not point any thing. When the cursor is
opened, memory is allocated and the cursor structure is created. The cursor variable now points the cursor.
When the cursor is closed the memory allocated for the cursor is released.
Cursors allow the programmer to retrieve data from a table and perform actions on that data one row at a
time. There are two types of cursors implicit cursors and explicit cursors.
Implicit cursors
For SQL queries returning single row PL/SQL declares implicit cursors. Implicit cursors are simple
SELECT statements and are written in the BEGIN block (executable section) of the PL/SQL. Implicit
cursors are easy to code, and they retrieve exactly one row. PL/SQL implicitly declares cursors for all DML
statements. The most commonly raised exceptions here are NO_DATA_FOUND or TOO_MANY_ROWS.
SELECT

ename,

sal

INTO

ena,

esa

FROM

EMP

WHERE

EMPNO

9589;

Note: Ename and sal are columns of the table EMP and ena and esa are the variables
used to store ename and sal fetched by the query.

25

Explicit Cursors :
Explicit cursors are used in queries that return multiple rows. The set of rows fetched by a query is called
active set. The size of the active set meets the search criteria in the select statement.
Explicit cursor is declared in the DECLARE section of PL/SQL program.
Syntax: CURSOR <cursor-name> IS <select statement>

Sample Code:
DECLARE
CURSOR emp_cur IS SELECT ename FROM EMP;
BEGIN
----

26

---END;
Processing multiple rows is similar to file processing. For processing a file you need to open it, process
records and then close. Similarly user-defined explicit cursor needs to be opened, before reading the rows,
after which it is closed. Like how file pointer marks current position in file processing, cursor marks the
current position in the active set.
Opening Cursor
Syntax: OPEN <cursor-name>;
Example : OPEN emp_cur;
When a cursor is opened the active set is determined, the rows satisfying the where clause in the select
statement are added to the active set. A pointer is established and points to the first row in the active set.
Fetching from the cursor: To get the next row from the cursor we need to use fetch statement.
Syntax: FETCH <cursor-name> INTO <variables>;
Example: FETCH emp_cur INTO ena;
FETCH statement retrieves one row at a time. Bulk collect clause need to be used to fetch more than one
row at a time.
Closing the cursor: After retrieving all the rows from active set the cursor should be closed. Resources
allocated for the cursor are now freed. Once the cursor is closed the execution of fetch statement will lead
to errors.
CLOSE <cursor-name>;
Explicit Cursor Attributes
Every cursor defined by the user has 4 attributes. When appended to the cursor name these attributes let the
user access useful information about the execution of a multi row query.
The attributes are:
1. %NOTFOUND: It is a Boolean attribute, which evaluates to true, if the last fetch failed. i.e. when
there are no rows left in the cursor to fetch.
2. %FOUND: Boolean variable, which evaluates to true if the last fetch, succeeded.
3.

%ROWCOUNT: Its a numeric attribute, which returns number of rows fetched by the cursor so
far.

27

4. %ISOPEN: A Boolean variable, which evaluates to true if the cursor is opened otherwise to false.

Example:
In above example we wrote a separate fetch for each row, instead loop statement could be used here.
Following example explains the usage of LOOP.

28

Using WHILE: While LOOP can be used as shown in the following example for accessing the cursor
values.

29

Using FOR LOOP :


The cursor for Loop can be used to process multiple records. There are two benefits with cursor for Loop
1. It implicitly declares a %ROWTYPE variable, also uses it as LOOP index
2. Cursor For Loop itself opens a cursor, read records then closes the cursor automatically. Hence OPEN,
FETCH and CLOSE statements are not necessary in it.
Example:

30

emp_rec is automatically created variable of %ROWTYPE. We have not used OPEN, FETCH , and
CLOSE in the above example as for cursor loop does it automatically.
The above example can be rewritten as shown as below, with less lines of code. It is called Implicit for
Loop.

31

Deletion or Updation Using Cursor:


In all the previous examples I explained about how to retrieve data using cursors. Now we will see how to
modify or delete rows in a table using cursors. In order to Update or Delete rows, the cursor must be
defined with the FOR UPDATE clause. The Update or Delete statement must be declared with WHERE
CURRENT
OF
sss
Following example updates comm of all employees with salary less than 2000 by adding 100 to existing
comm.

REF CURSOR

A REF CURSOR is basically a data type. A variable created based on such a data type is generally called a
cursor variable. A cursor variable can be associated with different queries at run-time. The primary
advantage of using cursor variables is their capability to pass result sets between sub programs (like stored
procedures, functions, packages etc.).
A REF CURSOR can be associated with more than one SELECT statement at run-time. Before associating
a new SELECT statement, we need to close the CURSOR. Let us have an example as follows:
declare
type r_cursor is REF CURSOR;
c_emp r_cursor;

32

type rec_emp is record


(
name varchar2(20),
sal
number(6)
);
er rec_emp;
begin
open c_emp for select ename,sal from emp where deptno = 10;
dbms_output.put_line('Department: 10');
dbms_output.put_line('--------------');
loop
fetch c_emp into er;
exit when c_emp%notfound;
dbms_output.put_line(er.name || ' - ' || er.sal);
end loop;
close c_emp;
open c_emp for select ename,sal from emp where deptno = 20;
dbms_output.put_line('Department: 20');
dbms_output.put_line('--------------');
loop
fetch c_emp into er;
exit when c_emp%notfound;
dbms_output.put_line(er.name || ' - ' || er.sal);
end loop;
close c_emp;
end;

In the above example is the following:


type rec_emp is record
(
name varchar2(20),
sal
number(6)
);

The above defines a new data type named "rec_emp" (just like %ROWTYPE with limited specified fields)
which can hold two fields, namely "name" and "sal."
Example 2:

Working with REF CURSOR inside loops


Sometimes, it may be necessary for us to work with REF CURSOR within loops. Let us consider the
following example:

33

declare
type r_cursor is REF CURSOR;
c_emp r_cursor;
type rec_emp is record
(
name varchar2(20),
sal
number(6)
);
er rec_emp;
begin
for i in (select deptno,dname from dept)
loop
open c_emp for select ename,sal from emp where deptno = i.deptno;
dbms_output.put_line(i.dname);
dbms_output.put_line('--------------');
loop
fetch c_emp into er;
exit when c_emp%notfound;
dbms_output.put_line(er.name || ' - ' || er.sal);
end loop;
close c_emp;
end loop;
end;
STRONG REF cursor and WEAK REF Cursor.
A strong REF CURSOR type definition specifies a return type, but a weak definition does not.

type r_cursor is REF CURSOR; -- Weak


type r_cursor is REF CURSOR return rec_emp;

Example :

-- Strong

Weak cursor

type r_cursor is REF CURSOR;


c_emp r_cursor;

-- Weak

type rec_emp is record


(
name varchar2(20),
sal
number(6)
);
er rec_emp;
Example : Strong cursor

34

type rec_emp is record


(
name varchar2(20),
sal
number(6)
);
er rec_emp;
type r_cursor is REF CURSOR return rec_emp;
c_emp r_cursor;

-- Strong

ANONYMOUS BLOCKS
An anonymous block is a PL/SQL program unit that has no name. An anonymous block consists of an
optional declarative part, an executable part, and one or more optional exception handlers.
The declarative part declares PL/SQL variables, exceptions, and cursors. The executable part contains
PL/SQL code and SQL statements, and can contain nested blocks. Exception handlers contain code that is
called when the exception is raised, either as a predefined PL/SQL exception (such as NO_DATA_FOUND
or ZERO_DIVIDE) or as an exception that you define.
The following short example of a PL/SQL anonymous block prints the names of all employees in
department 20 in the hr.employees table by using the DBMS_OUTPUT package:
DECLARE
Last_name
VARCHAR2(10);
Cursor c1 IS SELECT last_name
FROM employees
WHERE department_id = 20;
BEGIN
OPEN c1;
LOOP
FETCH c1 INTO Last_name;
EXIT WHEN c1%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(Last_name);
END LOOP;
END;
/

35

STORED PROCEDURES
What is a Stored Procedure?

A stored procedure or in simple a proc is a named PL/SQL block which performs one or more specific
task. This is similar to a procedure in other programming languages. A procedure has a header and a body.
The header consists of the name of the procedure and the parameters or variables passed to the procedure.
The body consists or declaration section, execution section and exception section similar to a general
PL/SQL Block. A procedure is similar to an anonymous PL/SQL Block but it is named for repeated usage.
We can pass parameters to procedures in three ways.
1. IN parameters

2. OUT parameters

3. IN OUT - parameters
A procedure may or may not return any value.
General Syntax to create a procedure is:
CREATE [OR REPLACE] PROCEDURE proc_name [list of parameters]
IS
Declaration section
BEGIN
Execution section
EXCEPTION
Exception section
END;

IS - marks the beginning of the body of the procedure and is similar to DECLARE in anonymous PL/SQL
Blocks. The code between IS and BEGIN forms the Declaration section.
The syntax within the brackets [ ] indicate they are optional. By using CREATE OR REPLACE together
the procedure is created if no other procedure with the same name exists or the existing procedure is
replaced with the current code.

36

The below example creates a procedure employer_details which gives the details of the employee.
create or replace procedure employer_details
is
cursor emp_cur is
select first_name, last_name, salary from emp_tbl;
emp_rec emp_cur%rowtype;
begin
for emp_rec in sales_cur
loop
dbms_output.put_line(emp_cur.first_name || ' '
||emp_cur.last_name || ' '
||emp_cur.salary);
end loop;
end;
/
How to execute a Stored Procedure?

There are two ways to execute a procedure.


1) From the SQL prompt.
EXECUTE [or EXEC] procedure_name;
SQL> EXECUTE employer_details;

2) Within another procedure simply use the procedure name.


procedure_name;

NOTE: In the examples given above, we are using backward slash / at the end of the program. This
indicates the oracle engine that the PL/SQL program has ended and it can begin processing the statements.
Parameters in Procedures
How to pass parameters to Procedures and Functions in PL/SQL ?

In PL/SQL, we can pass parameters to procedures and functions in three ways.


1) IN type parameter: These types of parameters are used to send values to stored procedures.
2) OUT type parameter: These types of parameters are used to get values from stored procedures.
This is similar to a return type in functions.

37

3) IN OUT parameter: These types of parameters are used to send values and get values from stored
procedures.
NOTE: If a parameter is not explicitly defined a parameter type, then by default it is an IN type parameter.
1) IN parameter:
This is similar to passing parameters in programming languages. We can pass values to the stored
procedure through these parameters or variables. This type of parameter is a read only parameter. We can
assign the value of IN type parameter to a variable or use it in a query, but we cannot change its value
inside the procedure.
The General syntax to pass a IN parameter is
CREATE [OR REPLACE] PROCEDURE procedure_name (
param_name1 IN datatype, param_name12 IN datatype ... )

param_name1, param_name2... are unique parameter names.

datatype - defines the datatype of the variable.

IN - is optional, by default it is a IN type parameter.

SQL> ED PROC1.SQL
CREATE OR REPLACE PROCEDURE DISPN (N IN NUMBER ) IS
BEGIN
DBMS_OUTPUT.PUT_LINE(N is || N);
END;
/
SQL> @ PROC1.SQL <enter>
SQL> EXECUTE DISPN (1234567891);
N is 1234567891

2) OUT Parameter:
The OUT parameters are used to send the OUTPUT from a procedure or a function. This is a write-only
parameter i.e, we cannot pass values to OUT paramters while executing the stored procedure, but we can
assign values to OUT parameter inside the stored procedure and the calling program can recieve this output
value.

Syntax : CREATE [OR REPLACE] PROCEDURE proc2 (param_name OUT datatype)

38

The parameter should be explicity declared as OUT parameter. we simply specify OUT in between the parameter
name and its type.

Example:
SQL> ed OUT_PROC.SQL
create or replace procedure sum_ab(a in number, b in number, c out number) is
begin
c := a + b;
end;
/
Notice that the above code does not display the resulting sum, it just changes the value of the C parameter. Also notice the word
OUT right after the declaration of C parameter name.
Anyway, we will use a code fragment to call the procedure:
SQL> ED <filename>.sql

declare
r number;
begin
sum_ab(50,60,r);
dbms_output.put_line(sum is: || r);
end;
/
SQL> @ FILNAME.SQL
Which when ran, displays:
19
SUM IS: 52
Notice how we called the procedure with an argument to eventually retrieve the OUT result.

The below examples show how to create stored procedures using the above three types of parameters. Lets
create a procedure which gets the name of the employee when the employee id is passed.

create or replace procedure emp_name (id in number, emp_name out number) is

39

begin
select first_name into emp_name
from emp_tbl where empid = id;
end;
/
We can call the procedure emp_name in this way from a PL/SQL Block.
declare
empname varchar(20);
cursor id_cur select id from emp_ids;
begin
for emp_rec in id_cur
loop
emp_name(emp_rec.id, empname);
dbms_output.putline('the employee '||empname||' has id '||emp-rec.id);
end loop;
end;
/
In the above PL/SQL Block
In line no 3; we are creating a cursor id_cur which contains the employee id.
In line no 7; we are calling the procedure emp_name, we are passing the id as IN parameter and
empName as OUT parameter.
In line no 8; we are displaying the id and the employee name which we got from the procedure
emp_name.

3) IN OUT Parameter:

The IN OUT parameter allows us to pass values into a procedure and get output values from the procedure.
This parameter is used if the value of the IN parameter can be changed in the calling program. By using IN
OUT parameter we can pass values into a parameter and return a value to the calling program using the
same parameter. But this is possible only if the value passed to the procedure and output value have a same
data type. This parameter is used if the value of the parameter will be changed in the procedure.

40

The General syntax to create an IN OUT parameter is


CREATE [OR REPLACE] PROCEDURE proc2 (param_name IN OUT datatype)

create or replace procedure emp_salary_increase


(emp_id in emptbl.empid%type, salary_inc in out emptbl.salary%type)is
tmp_sal number;
begin
select salary
into tmp_sal
from emp_tbl
where empid = emp_id;
if tmp_sal between 10000 and 20000 then
salary_inout := tmp_sal * 1.2;
elsif tmp_sal between 20000 and 30000 then
salary_inout := tmp_sal * 1.3;
elsif tmp_sal > 30000 then
salary_inout := tmp_sal * 1.4;
end if;
end;
/
The below PL/SQL block shows how to execute the above 'emp_salary_increase' procedure.

declare
cursor updated_sal is
select empid,salary
from emp_tbl;
pre_sal number;
begin
for emp_rec in updated_sal loop
pre_sal := emp_rec.salary;
emp_salary_increase(emp_rec.empid, emp_rec.salary);
dbms_output.put_line('the salary of ' || emp_rec.empid ||
' increased from '|| pre_sal || ' to '||emp_rec.salary);
end loop;
end;
/

41

Example : write a procedure that doubles a number:


create or replace procedure doublen (n in out int) is
begin
n := n * 2;
end;
To run it, we also create a small code fragment:
declare
r number;
begin
r := 7;
dbms_output.put_line(before call r is: || r);
doublen(r);
dbms_output.put_line(after call r is: || r);
end;
Which when ran displays:
BEFORE CALL R IS: 7
AFTER CALL R IS: 14

Notice how this particular call first grabbed the value of a parameter, then set it in order to return the
double of the value.
You can generally intermix these various ways of passing parameters (along with various types). You can
use these to setup return values from procedures, etc.

FUNCTIONS
Functions are special types of procedures that have the capability to return a value.
42

It is a very shady question of when to use what, either functions or procedures. A good rule of thumb is: if
youre interested in the results of the code, then you use a function, and return those results. If youre
interested in the side effects (like table updates, etc.) and not about the result when you should use a
procedure. Usually it doesnt affect your code all that much if you use a procedure or a function.
General Format
The general format of a function is very similar to the general format of a procedure:
CREATE [OR REPLACE] FUNCTION function_name [parameters]
RETURN return_datatype;
IS
Declaration_section
BEGIN
Execution_section
Return return_variable;
EXCEPTION
exception section
Return return_variable;
END;

1) Return Type: The header section defines the return type of the function. The return datatype can be
any of the oracle datatype like varchar, number etc.
2) The execution and exception section both should return a value which is of the datatype defined in
the header section.
Example 1: create a frunction called ''employer_details_func' similar to the one created in stored
proc
CREATE OR REPLACE FUNCTION employer_details_func
RETURN VARCHAR(20);
IS
emp_name VARCHAR(20);
BEGIN
SELECT first_name INTO emp_name
FROM emp_tbl WHERE empID = '100';
RETURN emp_name;
END;
/

In the example we are retrieving the first_name of employee with empID 100 to variable emp_name.
The return type of the function is VARCHAR which is declared in line no 2.
The function returns the 'emp_name' which is of type VARCHAR as the return value in line no 9.
How to execute a PL/SQL Function?
A function can be executed in the following ways.
1) Since a function returns a value we can assign it to a variable.

43

employee_name := employer_details_func;
If employee_name is of datatype varchar we can store the name of the employee by assigning the return
type of the function to it.
2) As a part of a SELECT statement
SELECT employer_details_func FROM dual;
3) In a PL/SQL Statements like,
dbms_output.put_line(employer_details_func);
Example 2: write a function that computes the sum of two numbers with arguments.
CREATE OR REPLACE FUNCTION add_two (a number, b number) return number is
begin
return (a + b);
end;
To run it, well write a small piece of code that calls this:
begin
dbms_output.put_line(result is: || add_two(12,34));
end;
Which produces the output:
RESULT IS: 46
(or)
SQL> select add_two(12,34) from dual; <enter>
46

Example 3: get_bal function returns the balance of a specified account.


CREATE FUNCTION get_bal(acc_no IN NUMBER)

44

RETURN NUMBER
IS acc_bal NUMBER(11,2);
BEGIN
SELECT order_total
INTO acc_bal
FROM orders
WHERE customer_id = acc_no;
RETURN(acc_bal);
END;
/
The get_bal function returns the balance of a specified account.
When you call the function, you must specify the argument acc_no, the number of the account whose
balance is sought. The datatype of acc_no is NUMBER.
The function returns the account balance. The RETURN clause of the CREATE FUNCTION statement
specifies the datatype of the return value to be NUMBER.
The function uses a SELECT statement to select the balance column from the row identified by the
argument acc_no in the orders table. The function uses a RETURN statement to return this value to the
environment in which the function is called.
The function created in the preceding example can be used in a SQL statement. For example:
SELECT get_bal(165) FROM DUAL;
GET_BAL(165)
-----------2519

PACKAGES
A package is a schema object that groups logically related PL/SQL types, variables, and subprograms.
Packages usually have two parts, a specification (spec) and a body; sometimes the body is unnecessary.
45

The specification is the interface to the package. It declares the types, variables, constants, exceptions,
cursors, and subprograms that can be referenced from outside the package. The body defines the queries for
the cursors and the code for the subprograms.
To create package specs, use the SQL statement CREATE PACKAGE. A CREATE PACKAGE BODY
statement defines the package body.
The spec holds public declarations, which are visible to stored procedures and other code outside the
package. You must declare subprograms at the end of the spec after all other items (except pragmas that
name a specific function; such pragmas must follow the function spec).
The body holds implementation details and private declarations, which are hidden from code outside the
package. Following the declarative part of the package body is the optional initialization part, which holds
statements that initialize package variables and do any other one-time setup steps.
Advantages of PL/SQL Packages

Packages offer several advantages: modularity, easier application design, information hiding, added
functionality, and better performance.

Modularity
Packages let you encapsulate logically related types, items, and subprograms in a named PL/SQL module.
Each package is easy to understand, and the interfaces between packages are simple, clear, and well
defined. This aids application development.

Easier Application Design


When designing an application, all you need initially is the interface information in the package specs. You
can code and compile a spec without its body. Then, stored subprograms that reference the package can be
compiled as well. You need not define the package bodies fully until you are ready to complete the
application.

Information Hiding
With packages, you can specify which types, items, and subprograms are public (visible and accessible) or
private (hidden and inaccessible). For example, if a package contains four subprograms, three might be
public and one private. The package hides the implementation of the private subprogram so that only the
package (not your application) is affected if the implementation changes. This simplifies maintenance and
enhancement. Also, by hiding implementation details from users, you protect the integrity of the package.

Added Functionality
Packaged public variables and cursors persist for the duration of a session. So, they can be shared by all
subprograms that execute in the environment. Also, they allow you to maintain data across transactions
without having to store it in the database.
46

Better Performance
When you call a packaged subprogram for the first time, the whole package is loaded into memory. So,
later calls to related subprograms in the package require no disk I/O. Also, packages stop cascading
dependencies and thereby avoid unnecessary recompiling. For example, if you change the implementation
of a packaged function, Oracle need not recompile the calling subprograms because they do not depend on
the package body.
Summary :
1. Packages encapsulate related functionality into one self-contained unit.
2. Packages are typically made up of two components: a specification and a body.
3. The package specification contains information about the package.
4. The package specification lists the available procedures and functions.
5. These are potentially available to all database users.
6. The package specification generally doesn't contain the code.
7. The package body contains the actual code.

Example 1: A Sample package with a function and procedure.


SQL> pack_spec.sql
CREATE OR REPLACE PACKAGE pkg_test1
as
function getArea (i_rad NUMBER) return NUMBER;
procedure p_print (i_str1 VARCHAR2 :='hello',
i_str2 VARCHAR2 :='world',
i_end VARCHAR2 :='!' );
end;
/
SQL> @ pack1.sql <enter>
Package created.
SQL> ed pack_body.sql
CREATE OR REPLACE PACKAGE BODY pkg_test1
47

as
function getArea (i_rad NUMBER)return NUMBER
is
v_pi NUMBER:=3.14;
begin
return v_pi * (i_rad ** 2);
end;
procedure p_print(i_str1 VARCHAR2 :='hello',
i_str2 VARCHAR2 :='world',
i_end VARCHAR2 :='!' )
is
begin
DBMS_OUTPUT.put_line(i_str1||','||i_str2||i_end);
end;
end;
/
SQL> @ pack_body.sql
Package body created.
SQL> select pkg_test1.getarea(90) from dual; -- execute the function from package
SQL> execute pkg_test1.p_print;

-- execute the procedure from the package

Example 2: Bank balance and transactions


/* Package specification */
CREATE PACKAGE bank_transactions (null) as

function show_bal (accno number) ;


procedure credit_account(acct number, credit number);

END bank_transactions

48

create package body bank_transactions as

/* This function to return the balance in the account */


create function show_bal (accno number) return number is
begin
select balance
into

available_balance

from accounts
where bank_accno = accno;
return (available_balance);
end;

/* This procedure accepts two arguments: an account number and an


amount of money to credit to the specified account. If the
specified account does not exist, a new account is created. */

create procedure credit_account (acct number, credit number) as


old_balance NUMBER;
new_balance NUMBER;
begin
select balance into old_balance from accounts
where acct_id = acct for update of balance;

49

new_balance := old_balance + credit;

update accounts set balance = new_balance


where acct_id = acct;
commit;

exception
when no_data_found then
insert into accounts (acct_id, balance) values(acct, credit);

when others then


rollback;
end credit_account;
Example 3: using ref cursor to show dept and emp details
Package Specification :
create or replace package curspkg as
type t_cursor is ref cursor;
procedure open_one_cursor (n_empno in number, io_cursor in out t_cursor);
procedure open_two_cursors (empcursor out t_cursor, deptcursor out t_cursor);
end curspkg;
/
Package body :

create or replace package body curspkg as


procedure open_one_cursor (n_empno in number, io_cursor in out t_cursor) is
v_cursor t_cursor;
begin

50

if n_empno <> 0
then
open v_cursor for
select emp.empno, emp.ename, dept.deptno, dept.dname
from emp, dept
where emp.deptno = dept.deptno
and emp.empno = n_empno;
else
open v_cursor for
select emp.empno, emp.ename, dept.deptno, dept.dname
from emp, dept
where emp.deptno = dept.deptno;
end if;
io_cursor := v_cursor;
end open_one_cursor;
procedure open_two_cursors (empcursor out t_cursor, deptcursor out t_cursor) is
v_cursor1 t_cursor;
v_cursor2 t_cursor;
begin
open v_cursor1 for select * from emp;
open v_cursor2 for select * from dept;
empcursor := v_cursor1;
deptcursor := v_cursor2;
end open_two_cursors;
end curspkg;
/

51

Das könnte Ihnen auch gefallen