4 Quick Reference-PLSQL

You might also like

Download as doc, pdf, or txt
Download as doc, pdf, or txt
You are on page 1of 66

Oracle Complete – A Quick Reference

PL/SQL

PL/SQL Block
PL/SQL Block is a structured block of code having a declaration section to declare
variables, a begin to write the executable commands, an exception handling section and
finally the end.

Declare
<Declare variables>
Begin
<Executable commands>
Exception
<Exception handlers>
End;

Displaying Output on the Terminal


In every session of the PL/SQL the following SQL Plus command must be typed at the
SQL prompt.

Set Serveroutput On

If this command is not typed, the output of the code will not be displayed on the terminal.

If some output of your block is to be written on the terminal screen, you should use
DBMS_OUTPUT.PUT_LINE(<what to write>);
in the PL/SQL block. Examples are shown below.

Data Types
Char
Varchar2
Number,
Boolean

The Boolean data type is used with Yes / No type variables like
V_Married Boolean;

Variable Declaration

Thampy Mathew 132


Oracle Complete – A Quick Reference
PL/SQL
All variables must be declared in the declaration section of a block. This doesn’t mean
that all variables of a program must be declared at the top of it. One program may be
made up of several independent blocks or nested blocks (one block within another block).
The variables of each block must be declared at its top.

Example – Variables in Multiple Independent Blocks

-- Block 1

Declare

V_Name Varchar2(20);
V_No Number;

Begin
<Coding>
Exception
<Handler>
End;

-- Block 2

Declare

V_Dept Varchar2(20);
V_Deptno Number;

Begin
<Coding>
Exception
<Handler>
End;

Example – Variables in Nested Blocks

-- Block 1

Declare

V_Name Varchar2(20);
V_No Number;

Begin
<Coding>

Thampy Mathew 133


Oracle Complete – A Quick Reference
PL/SQL
-- Block 2 Within Block 1

Declare

V_Dept Varchar2(20);
V_Deptno Number;

Begin
<Coding>
Exception
<Handler>
End;

<Coding>

Exception
<Handler>
End;

Example – Variables in Nested and Independent Blocks

-- Block 1

Declare

V_Name Varchar2(20);
V_No Number;

Begin
<Coding>

-- Block 2 Within Block 1

Declare

V_Dept Varchar2(20);
V_Deptno Number;

Begin
<Coding>
Exception
<Handler>
End;

Thampy Mathew 134


Oracle Complete – A Quick Reference
PL/SQL
<Coding>

Exception
<Handler>
End;

-- Block 3

Declare

V_SumSal Number;

Begin
<Coding>
Exception
<Handler>
End;

Initializing or Assigning Values to Variables.

At the time of declaring a variable you can assign an initial value to it as follows.

Declare

V_Sal1 Number := 0;
V_Sal2 Number := 0;

Or subsequently when a value is to be assigned, it should be:

V_Sal1 := V_Sal2;

For assigning a value to a variable use :=

Taking User Input to Initialize a Variable

Declare
V_Sal1 Number := &A;
V_Sal2 Number := &B;

Assigning the Output of a Query to Variables

Thampy Mathew 135


Oracle Complete – A Quick Reference
PL/SQL
Declare

V_Empno Number;
V_Ename Varchar2(20);

Begin

Select Empno, Ename INTO V_Empno, V_Ename


From EMP
Where Empno = 1000;

DBMS_OUTPUT.PUT_LINE (V_Empno ||’ ‘|| V_Ename);

End;

Caution:
In the above given type of assignment you should ensure the following.

1. The data type of the selected field and its variable must match
2. The data width of the variable must be more than or equal to the field width.
3. The query should not return more than one record. (If the query returns more
than one record it should be handled by a Cursor or a %ROWTYPE or
%TYPE type of variables discussed later.

Comparing Variable Values

If V_Sal1 = V_Sal2 Then OR


If V_Sal2 > 1000 Then OR
If V_Sal1 <= V_Sal2 etc.

For comparing the value of a variable use =

Incrementing Variable Values

V_Sal1 := V_Sal1 + 1

Meaning of the above statement is that assign a value to the variable V_Sal1 which
should be equal to the current value in the variable V_Sal1 + 1. So, if the current value in
V_Sal1 is 0, after the execution of the code, it will become 1 (V_Sal1 := 0 + 1).

Dynamic Data Types

Thampy Mathew 136


Oracle Complete – A Quick Reference
PL/SQL
For creating multiple variables in a single declaration, you can use Dynamic Data Types.
The Dynamic Data Types are:

%ROWTYPE
%TYPE

In PL/SQL these data types are used to hold values of several fields fetched by a select
statement. When a variable is created using any of these data types a database table name
must be used in the declaration.

%ROWTYPE
This data type will automatically create that many variables equal to the number of
columns specified in the declaration. The names and data types of the auto created
variables will be same as that of the names and data types of the columns of the specified
table.

Once a set of variables is created, it becomes independent of the table from which hey are
created. You can fetch values fro another table into these variables provided that the
number of columns and the data types match.

Declare

V_Emp EMP%ROWTYPE;

Explanation:

V_Emp is the collective name of all the variables that the system creates by the
declaration.

EMP is the name of the table from where the variables are to be created.

ROW tells the system to inherit the field names as names for the variables it creates.

TYPE tells the system to inherit the data types of the fields as data types of the variables
it creates.

Referencing the %ROWTYPE Variable.

Declare

V_Emp EMP%ROWTYPE;

Begin

Thampy Mathew 137


Oracle Complete – A Quick Reference
PL/SQL
Select * INTO V_Emp
From EMP
Where Empno = 1000;

DBMS_OUTPUT.PUT_LINE (V_Emp.Empno ||’ ‘|| V_Emp.Ename);

End;

%TYPE

This is similar to %ROWTYPE. The %ROWTYPE cannot be used to create variables


only for a few fields of a table. It will always create variables for all the fields of the
specified table. Sometimes, you may require variables only for a few fields of a table. It
can be declared directly as a normal variable, but if you directly define the variable, you
must know the data type and width of the field for which the variables are created.
Knowing the data type and width of the required fields may not be known many times. In
such situations, you can use the %TYPE data type to inherit only the data type and width
of a few fields of a table.

As the variables are created only for a few fields of a table, you have to specify the field
names in the declaration.

Declare

V_Emp_Empno EMP.Empno%TYPE;
V_Emp_Ename EMP.Ename%TYPE;

Referencing the %TYPE Variable.

Declare

V_Emp_Empno EMP.Empno%TYPE;
V_Emp_Ename EMP.Ename%TYPE;

Begin

Select Empno, Ename INTO V_Emp_Empno, V_Emp_Ename


From EMP
Where Empno = 1000;

DBMS_OUTPUT.PUT_LINE (V_Emp_Empno || V_Emp_Ename);

End;

Thampy Mathew 138


Oracle Complete – A Quick Reference
PL/SQL

User Defined Data Types

TYPE EMP_DT IS RECORD


(V_Empno Number,
V_Ename Varchar2(20));

V_Emp_Cols EMP_DT;

Explanation:

TYPE Key Word


EMP_DT User specified name for the data type
IS RECORD Key Words
(V_Empno Number Individual variable name and its data type
V_Ename Varchar2(20) Individual variable name and its data type

V_Emp_Cols EMP_DT A collective name for all the individual variables with the
user specified data type.

Declare

Type Emp_DT Is Record


(Empno Number,
Ename Varchar2(20));

V_Emp_Cols Emp_DT;

Begin

Select Empno, Ename INTO V_Emp_cols


From EMP
Where Ename = 'SMITH';

DBMS_OUTPUT.PUT_LINE(V_Emp_Cols.Ename|| V_Emp_Cols.Empno );

End;

Caution:
The data type and width of the individual variables must be more than or equal t
he field data type and width for which it is created.

Thampy Mathew 139


Oracle Complete – A Quick Reference
PL/SQL

Combined Use of Dynamic And User Defined


Data Types
Declare

Type EMP_DT Is Record


(V_Sal Number,
V_Ename EMP.Ename%TYPE);

V_Emp_Cols EMP_DT;

Begin

Select Sal, Ename INTO V_Emp_Cols.V_Sal, V_Emp_Cols.V_Ename


From EMP
Where Ename = ‘SMITH’;

DBMS_OUTPUT.PUT_LINE(V_Emp_Cols.V_Ename|| V_Emp_Cols.Sal );

End;

Declare

Type EMP_DT Is Record


(V_Dname Vrchar2(10),
V_Emp EMP%ROWTYPE);

V_Emp_Cols EMP_DT;

Begin

Select Dname, INTO V_Emp_Cols.V_Dname


From DEPT
Where Deptno = ‘10’;

Select * INTO V_Emp_Cols.V_Emp


From EMP
Where Ename = ‘SMITH’;

DBMS_OUTPUT.PUT_LINE(
V_Emp_Cols.V_Dname || V_Emp_Cols.V_EMP.Ename );

Thampy Mathew 140


Oracle Complete – A Quick Reference
PL/SQL
End;

Nested Data Type


Declare

Type 10_CHR Is Record


(Field1 Varchar2(10));

Type CHR_NUM Is Record


(Field1 Number,
Field2 10_CHR);

V_Var CHR_NUM

Begin

Select Empno, Ename INTO V_Var.Field1, V_Var.Field2.Field1


From EMP
Where Ename = ‘KING’;

DBMS_OUTPUT.PUT_LINE(V_Var.Field1 || ‘ ‘ || V_Var.Field2.Field1);

End;

Taking User Input in PL/SQL Blocks


For taking user input, you can create a Bind Variable as follows.

Declare

V_Ename Varchar2(20);

Begin

Select Ename INTO V_Ename


From EMP
Where Empno = &No;

DBMS_OUTPUT.PUT_LINE (V_Ename);

Thampy Mathew 141


Oracle Complete – A Quick Reference
PL/SQL
End;

The &No is the bind variable defined in the block to accept user input. Every time when
this block is executed the user will be asked to enter No and with that input, the rest of
the code will be executed.

Specifying Conditions in PL/SQL Blocks


For specifying condtions, the IF statement is used

Syntax:

1. If <condition> Then
End If;

2. If <condition> Then
<Code>
Else
<Code>
End If;

3. If <condition> Then
<Code>
Elsif <condition> Then
<Code>
Elsif <condition> Then
<Code>
Else
<Code>
End If;

Nested Conditions

If <condition> Then
<Code>

IF <condition> THEN
<Code>
ELSIF <condition> THEN
<Code>
ELSIF <condition> THEN
<Code>
ELSE
<Code>

Thampy Mathew 142


Oracle Complete – A Quick Reference
PL/SQL
ENDIF;

<Code>

Elsif <condition> Then


<Code>
Elsif <condition> Then
<Code>

IF <condition> THEN
<Code>
ELSIF <condition> THEN
<Code>

IF <condition> THEN
<Code>
END IF;

ELSIF <condition> THEN


<Code>
ELSE
<Code>
END IF;

Else
<Code>
End If;

Example:

Declare

V_Ename Varchar2(20);

Begin

Select Ename INTO V_Ename


From EMP
Where Empno = &No;

IF V_Ename = ‘SMITH’ THEN

DBMS_OUTPUT.PUT_LINE (V_Ename);

ELSIF V_Ename = ‘BLAKE’ THEN

Thampy Mathew 143


Oracle Complete – A Quick Reference
PL/SQL
V_Ename := Mr. || V_Ename;

DBMS_OUTPUT.PUT_LINE (V_Ename);

END IF;

End;

Cursor
We have already seen several type of variable declarations to hold single value and
multiple values. But all those variables can hold only one value at a time. What about
holding multiple records from several fields of one or more tables. Declare a CURSOR is
the answer.

A CURSOR dynamically creates that many individual variable with the same name, data
type and data width as that of the fields involved in the Select statement of the Cursor.
The Cursor name acts as a collective name for all those individual variables.

Declare

Cursor C1 Is Select * From EMP;

Explanation:

Cursor Key word


C1 Cursor name
Is Select * From EMP The select statement that creates the Cursor.
Dynamically it creates one variable with the same name, data type and width of those
columns that are involved with the query. Unlike other variables, these dynamically
created variables can store any number of records that the query fetches. Similarly, you
cannot assign values to these variables manually. All records returned by the query will
be assigned to its respective field variable implicitly.

Declare

Cursor C1 Is Select D.Dname, E.Ename, E.Empno, E.Sal


From DEPT D, EMP E
Where D.Deptno = E.Deptno;

Attributes of Cursor
%FOUND
%NOTFOUND

Thampy Mathew 144


Oracle Complete – A Quick Reference
PL/SQL
%ROWCOUNT
%ISOPEN

%FOUND

This attribute is used to check whether there is any records present in the Cursor.

%NOTFOUND

This attribute also is used to check whether there is any records present in the Cursor.

%ROWCOUNT

This attribute returns the count of the number of rows present in the cursor.

%ISOPEN

This attribute is used to check whether the cursor is currently open or not.

Examples are demonstrated in the section Iteration.

What Is Not Possible In a Cursor

Exceptions are not possible in a Cursor Except CURSOR_ALREADY_OPEN and


CURSOR_INVALID.

Implicit Cursor
With every DML operation, system automatically creates a cursor with the name SQL.
We can reference the value of this cursor like any user defined cursor. Refer ‘Referencing
Implicit Cursor’ below.

Loops in PL/SQL Blocks


Loops are used to execute the same code again and again. There are three types of Loops
that can be used in PL/SQL procedures.

Simple Loops
For Loops
While Loops

Thampy Mathew 145


Oracle Complete – A Quick Reference
PL/SQL
Simple Loops
Declare
V_No Number := 0;

Begin

Loop
DBMS_OUTPT.PUT_LINE (V_No);
Exit When V_No = 10;
V_No := V_No + 1;
End Loop;

End;

This loop will print V_No 11 times from 0 to 10.

Declare

V_No Number := 0;

Begin

Loop
Exit When V_No = 10;
DBMS_OUTPT.PUT_LINE (V_No);
V_No := V_No + 1;
End Loop;

End;

This loop will print V_No 10 times from 0 to 9.

Declare

V_No Number := 0;

Begin

Loop
V_No := V_No + 1;
Exit When V_No = 10;
DBMS_OUTPT.PUT_LINE (V_No);
End Loop;

Thampy Mathew 146


Oracle Complete – A Quick Reference
PL/SQL
End;

This loop will print V_No 9 times from 1 to 9.

Thampy Mathew 147


Oracle Complete – A Quick Reference
PL/SQL
Declare
V_No Number := 0;

Begin

Loop
V_No := V_No + 1;
DBMS_OUTPT.PUT_LINE (V_No);
Exit When V_No = 10;
End Loop;

End;

This loop will print V_No 10 times from 1 to 10.

Endless Loops

Declare
V_No Number := 0;

Begin

Loop
V_No := V_No + 1;
DBMS_OUTPT.PUT_LINE (V_No);
End Loop;

End;

For Loops
Forward For Loop

Begin

For I In 1 .. 10 Loop
DBMS_OUTPT.PUT_LINE (I);
End Loop;

End;

The data type of the variable I is %ROWTYPE.

Thampy Mathew 148


Oracle Complete – A Quick Reference
PL/SQL
Reverse For Loop

Begin

For I In Reverse 1 .. 10 Loop


DBMS_OUTPT.PUT_LINE (I);
End Loop;

End;

While Loops
Declare
V_No Number := 0;

Begin

While V_No < 10 Loop


DBMS_OUTPT.PUT_LINE (V_No);
V_No := V_No + 1;
End Loop;

End;

Cursor In For Loops


Transferring Data From One Table To Another

Create Table Bonus


(Ename Varchar2(20),
Bonus Number);

Declare

Cursor C1 Is Select Ename, Sal From EMP;

Begin

For I In C1 Loop
Insert Into Bonus Values (I.Ename, I.Sal * 0.1) ;
End Loop;

End;

Thampy Mathew 149


Oracle Complete – A Quick Reference
PL/SQL
Performing Calculations On Cursor Values

Declare

Cursor C1 Is Select Ename, Sal, Hiredate From EMP;

Begin

For I In C1 Loop
If Sysdate - I.Hiredate > 1 Then
Insert Into Bonus Values (I.Ename, I.Sal * 0.1) ;
EndIf;
End Loop;

Commit;

End;

Note:
Cursor will be automatically opened and closed in For Loops.

Using Aliases in Cursor

Declare
V_Val Number := 1;
Cursor C1 Is Select (Sal + V_Val) Salary From EMP;

Begin

For I in C1 Loop

DBMS_OUTPUT.PUT_LINE (I.Salary);

V_Val := V_Val + 1;

End Loop;

DBMS_OUTPUT.PUT_LINE (V_Val);

End;

Thampy Mathew 150


Oracle Complete – A Quick Reference
PL/SQL
Note:
The printed salaries will be Salary + 1 only though the variable X is getting
incremented in every execution of the loop. If DBMS_OUTPUT.PUT_LINE
(I.Salary) is re-written as DBMS_OUTPUT.PUT_LINE (I.Salary + X) the first
Salary would be Salary + 1, the second Salary would be Salary + 2 and so on.

If aliases are used for the fields in the select statement of the cursor, reference to
that variable must be with the alias.

Testing Cursor Open/Close Status in For Loops After Cursor Execution

Declare
V_Val Number := 1;
Cursor C1 Is Select (Sal + V_Val) Salary From EMP;

Begin

For I in C1 Loop

DBMS_OUTPUT.PUT_LINE (I.Salary);

V_Val := V_Val + 1;

End Loop;

DBMS_OUTPUT.PUT_LINE (V_Val);

If C1%ISOPEN Then

DBMS_OUTPUT.PUT_LINE (‘Cursor Open’);

Else

DBMS_OUTPUT.PUT_LINE (‘Cursor Closed’);

End If;

End;

Output: Cursor Closed

Note:
The For Loop closes the cursor automatically when comes out of the loop.

Thampy Mathew 151


Oracle Complete – A Quick Reference
PL/SQL
Multiple Cursors And Nested Loops

Declare

Cursor C1 Is Select * From EMP


Where Ename = 'SMITH' Or Ename = 'BLAKE';

Cursor C2 Is Select * From DEPT;

Begin

For I In C1 Loop

For J In C2 Loop
DBMS_OUTPUT.PUT_LINE (J.Dname ||' Department');
End Loop;

DBMS_OUTPUT.PUT_LINE (I.Ename ||' Employee');

End Loop;

End;

Output:
ACCOUNTING Department
RESEARCH Department
SALES Department
OPERATIONS Department

SMITH Employee

ACCOUNTING Department
RESEARCH Department
SALES Department
OPERATIONS Department

BLAKE Employee

Cursor In Simple Loops


Declare
V_Emp EMP%ROWTYPE;
Cursor C1 Is Select * From EMP;

Thampy Mathew 152


Oracle Complete – A Quick Reference
PL/SQL
Begin

Open C1 ;

Loop
Fetch C1 INTO V_Emp;
Exit When C1%NOTFOUND;

If Sysdate - I.Hiredate > 1 Then


Insert Into Bonus Values (I.Ename, I.Sal * 0.1) ;
End If;
End If;

End Loop

DBMS_OUTPUT.PUT_LINE (C1%ROWCOUNT);

Close C1;

Commit;

End;

Caution:
1. If the Cursor is used in a simple Loop, you must define a dynamic or user
defined type variable with the same number of child variables as that of the
fields involved in the cursor query. This is not applicable if the cursor is used
in a For Loop because by default the data type of the variable specified in the
For Loop is of %ROWTYPE.

2. The number of fields of the cursor and the number of child variables in the
Variable to which the records are fetching must be equal.

3. Before fetching values to the variable from the cursor, it must be opened with
an Open Statement.

4. Each row of record must be brought to the variable from the cursor using the
Fetch statement. After processing the fetched row, the next row should be
fetched and because of this he Fetch statement should come within the loop.

5. The Close statement should be outside the loop.

Thampy Mathew 153


Oracle Complete – A Quick Reference
PL/SQL
Note:
The Fetch statement will bring only one record at a time. Remember that except
for the cursor no other variable can hold more than one record at a time.

In a For Loop the Cursor will be closed automatically after executing the loop.

In a simple Loop the cursor remains open eve after executing the loop. It must be
closed with a Close statement.

Testing Cursor Open/Close Status in Simple Loops After Cursor Execution

Declare

Cursor C1 Is Select * From EMP;


V_Emp EMP%ROWTYPE;

Begin
Open C1;

Loop
Fetch C1 INTO V_Emp;

Exit When C1%NOTFOUND;

DBMS_OUTPUT.PUT_LINE (V_Emp.Ename);

End Loop;

If C1%ISOPEN Then
DBMS_OUTPUT.PUT_LINE ('Cursor Open');

Else
DBMS_OUTPUT.PUT_LINE ('Cursor Closed');

End If;

End;

Output: Cursor Open

Note:
In a Simple Loop the cursor remains open even after the execution of the loop. It
should be closed with a Close statement.

Thampy Mathew 154


Oracle Complete – A Quick Reference
PL/SQL

Referencing Implicit Cursor Values


Begin

Delete From Bonus Where Ename = 'SMITH';

If SQL%ROWCOUNT > 0 Then


DBMS_OUTPUT.PUT_LINE (SQL%ROWCOUNT || ' Rows Deleted');

Else
DBMS_OUTPUT.PUT_LINE ('No Record Found');

End If;

End;

Output: 3 Rows Deleted

Database Triggers
The database triggers are triggered before or after a DML event (Insert, Update, Delete).
Triggers can be created to trigger before or after processing each record of a DML
operation or only once before or after a DML operation. A trigger firing before or after
processing each row is called a Row Level Trigger whereas a trigger firing only once
before or after a DML operation is called a Statement Level Trigger

The triggers are stored in USER_TRIGGERS table.

The USER_TRIGGERS (DBA_TRIGGES) Table

DBA_TRIGGERS

Owner Varchar2(30) Not Null,


Trigger_Name Varchar2(30) Not Null,
Trigger_Type Varchar2(16),
Triggering_Event Varchar2(26),
Table_Owner Varchar2(30) Not Null,
Table_Name Varchar2(30) Not Null,
Referncing_Names Varchar2(87),
When_Clause Varchar2(4000),
Status Varchar2(8),
Description Varchar2(4000),
Trigger_Body Long

Thampy Mathew 155


Oracle Complete – A Quick Reference
PL/SQL
Set Long 40000

Select Triiger_Name, Tigger_Type, Staus, Trigger_Body


From User(DBA)_Triggers
Where Tregger_Name Like ‘%xxx%’ ;

Types of Triggers

Row Level Triggers Statement Level Triggers


1. Before Insert 1. Before Insert
2. After Insert 2. After Insert
3. Before Update 3. Before Update
4. After Update 4. After Update
5. Before Delete 5. Before Delete
6. After Delete 6. After Delete
Instead Of Trigger

Row Level Triggers


Before Insert – Row Level

Create Or Replace Trigger <Trigger Name>


Before Insert Or Update Or Delete On <Table Name> For Each Row

Declare
<Variables>
Begin
<Code>
Exception
<Exception Handlers>
End;

Limiting the Triggering Only On the Update of a Specific Column

Create Or Replace Trigger <Trigger Name>


Before Insert Or Update Of <Field1, Field2……> Or Delete
On <Table Name> For Each Row

Declare
<Variables>
Begin

Thampy Mathew 156


Oracle Complete – A Quick Reference
PL/SQL
<Code>
Exception
<Exception Handlers>
End;

After Insert – Row Level

Create Or Replace Trigger <Trigger Name>


After Insert Or Update Or Delete On <Table Name> For Each Row

Declare
<Variables>
Begin
<Code>
Exception
<Exception Handlers>
End;

Statement Level Triggers


Before Insert – Statement Level

Create Or Replace Trigger <Trigger Name>


Before Insert Or Update Or Delete On <Table Name>

Declare
<Variables>
Begin
<Code>
Exception
<Exception Handlers>
End;

After Insert – Statement Level

Create Or Replace Trigger <Trigger Name>


After Insert Or Update Or Delete On <Table Name>

Declare
<Variables>
Begin
<Code>
Exception
<Exception Handlers>
End;

Thampy Mathew 157


Oracle Complete – A Quick Reference
PL/SQL
Note:
The key words ‘For Each Row’ is added it becomes a Row Level Trigger else it
will be a Statement Level Trigger.

A Example For A Trigger That Handles All The 3 DML Operations

Create Or Replace Trigger BONUS


After Insert Or Update Or Delete On BONUS For Each Row

Declare
A Varchar2(25);

Begin

If Inserting Then
A := 'Inserted Successfully' ;
DBMS_OUTPUT.PUT_LINE (A) ;

Elsif Updating Then


A := 'Updated Successfully' ;
DBMS_OUTPUT.PUT_LINE (A) ;

Elsif Deleting Then


A := 'Deleted Successfully' ;
DBMS_OUTPUT.PUT_LINE (A) ;

End If;

End;

Note:
The trigger name can be the same as that of the table

An Example for Automatic Sequence Number Insertion

Create a Table
Create Table PUR_ORD
(PO_NUM Number Primary Key,
Item Varchar2(10) Not Null,
Qty Number,
Price Number,
Need_By Date);

Thampy Mathew 158


Oracle Complete – A Quick Reference
PL/SQL
Create a Sequence

Create Sequence PO_NUM ;

Create a Database Trigger

Create Or Replace Trigger PO_NUM


Before Insert On PUR_ORD For Each Row

Begin
Select PO_NUM.Nextval Into :NEW.PO_Num From Dual;
End;

Select * From PUR_ORD;

Output: no rows selected

Insert Into PUR_ORD Values('1000', 10, 51.5, '18-APR-2004');

Output: not enough values

Insert Into PUR_ORD (Item, Qty, Price, Need_By)


Values('1000', 10, 51.5, '18-APR-2004');

Output:
PO_NUM ITEM QTY PRICE NEED_BY
------ ----- ---- ----- ---------
48 1000 10 51.5 18-APR-04

See that the PO_NUM is inserted automatically.

Addressing the Incoming Values and Existing Values of a Field


In The Trigger Table

The incoming value of a field of the trigger table is addresed as :NEW.<Field Name>.
The existing value of a field of the trigger table is addressed as :OLD.<Field Name>.

When Inserting (creating new record) there will be only new values and hence you can
use only :NEW.<Field Name>.

When Updating there will be both old and new values and hence you can use both
:NEW.<Field Name> and :OLD.<Field Name>.

When Deleting there will be only old values and hence you can use only :OLD.<Field
Name>.

Thampy Mathew 159


Oracle Complete – A Quick Reference
PL/SQL

An Example for Automatic Other Values Insertion

Tracking The User Who Did It

Modify the PUR_ORD Table as follows.

Create Table PUR_ORD


(PO_NUM Number Primary Key,
Item Varchar2(10),
Qty Number,
Price Number,
Need_By Date,
Created_By Varchar2(20),
Creation_Date Date,
Updated_By Varchar2(20),
Update_Date Date);

Modify the PO_NUM Trigger as follows.

Create Or Replace Trigger PO_NUM


Before Insert Or Update On PUR_ORD For Each Row

Begin

If Inserting Then
Select PO_NUM.Nextval Into :NEW.PO_Num From Dual;
Select User Into :NEW.Created_By From Dual;
Select Sysdate Into :NEW.Creation_Date From Dual;
Select User Into :NEW.Updated_By From Dual;
Select Sysdate Into :NEW.Update_Date From Dual;

Elsif Updating Then


Select User Into :NEW.Updated_By From Dual;
Select Sysdate Into :NEW.Update_Date From Dual;

End If;

End;

Select * From PUR_ORD ;

Output: no rows selected

Thampy Mathew 160


Oracle Complete – A Quick Reference
PL/SQL
Insert Into PUR_ORD (Item, Qty, Price, Need_BY)
Values('1000', 10, 51.5, '18-APR-2004');

Select Created_By, Creation_Date, Updated_By, Update_Date


From PUR_ORD;

Output:
CREATED_BY CREATION UPDATED_BY UPDATE_DA
-------------------- --------- -------------------- ---------
SCOTT 26-JUL-03 SCOTT 26-JUL-03

An Example For Transferring Values From One Table To Another

Tracking Who Deleted

Create Table PO_DELETION_TRACKING


(PO_Num Number,
Deleted_By Varchar2(20),
Deletion_Date Date);

Alter the PO_NUM Trigger as follows.

Create Or Replace Trigger PO_NUM


Before Insert Or Update Or Delete On PUR_ORD For Each Row

Declare
V_User Varchar2(20);
V_Date Date;

Begin

If Inserting Then
Select PO_NUM.Nextval Into :NEW.PO_Num From Dual;
Select User Into :NEW.Created_By From Dual;
Select Sysdate Into : NEW.Creation_Date From Dual;
Select User Into : NEW.Updated_By From Dual;
Select Sysdate Into : NEW.Update_Date From Dual;

Elsif Updating Then


Select User Into : NEW.Updated_By From Dual;
Select Sysdate Into : NEW.Update_Date From Dual;

Elsif Deleting Then


Select User Into V_User From Dual;

Thampy Mathew 161


Oracle Complete – A Quick Reference
PL/SQL
Select Sysdate Into V_Date From Dual;

Insert Into PO_DELETION_TRACKING


Values(:OLD.PO_NUM, V_User, V_Date);

End If;

End;

Note:
1. To insert a new value to a field of the trigger table no Insert statement
is required. Only need to say :NEW.<Field Name> = <What>.

2. While inserting values into another table by picking values from the
trigger table, you should use the Insert statement.

Delete From PUR_ORD;

Select * From PO_DELETION_TRACKING;

Output:
PO_NUM DELETED_BY DELETION_
------ -------------------- ---------
49 SCOTT 26-JUL-03

An Example For Automatic Insertion Of Calculated Value Fields

Create Table EMP1


(Empno Number,
Sal Number,
PF Number,
Net Number);

Create Or Replace Trigger EMP1


Before Insert On EMP1 For Each Row

Begin

:NEW.PF := : NEW.Sal * 0.12;


: NEW.Net := : NEW.Sal - (:NEW.Sal * 0.12);
End;

Thampy Mathew 162


Oracle Complete – A Quick Reference
PL/SQL
Insert Into EMP1 (Empno, Sal)
Values (1023, 7500);

Insert Into EMP1 (Empno, Sal)


Values (1023, 7500);

Select * From EMP1;

Output:
EMPNO SAL PF NET
----- ------- ------ ---------
1023 7500 900 6600
1023 7500 900 6600

An Example For Statement Level Triggers

Create Or Replace Trigger EMP1


Before Insert On EMP1

Begin
DBMS_OUTPUT.PUT_LINE ('Deleted');
End;

An Example For Calling Procedures In Triggers

Table

Create Table EMP1


(Empno Number,
Sal Number);

Procedure

Create Or Replace Procedure EMP1_Insert


(Empno IN Number, Sal IN Number) As

Begin
Insert Into EMP1 Values (Empno, Sal);
End;

Trigger Calling The Procedure

Create Or Replace Trigger EMP

Thampy Mathew 163


Oracle Complete – A Quick Reference
PL/SQL
Before Insert On EMP For Each Row

Begin
Call EMP1_Insert (:NEW.Empno, :NEW.Sal);
End;

An Example For Mutating Error

Drop Table EMP1;

Note:
Dropping a Table will not drop the trigger on it.

Create Table EMP1


(Empno Number,
Sal Number);

Create Or Replace Trigger EMP1


Before Insert On EMP1 For Each Row

Declare
V_Sal Number;

Begin

Select Sal INTO V_Sal


From EMP1
Where Empno = :OLD.Empno;

Exception
When NO_DATA_FOUND Then
DBMS_OUTPUT.PUT_LINE ('Salary is not inserted');
End;

Insert Into EMP1 (Empno) Values(1003);

Select * From EMP1;

Output:
ERROR at line 1:
ORA-04091: table SCOTT.EMP1 is mutating, trigger/function may not see it
ORA-06512: at "SCOTT.EMP1_UP", line 4
ORA-04088: error during execution of trigger 'SCOTT.EMP1_UP'

Thampy Mathew 164


Oracle Complete – A Quick Reference
PL/SQL
An Example For Exception Handling

Drop Table EMP1;

Note:
Dropping a Table will not drop the trigger on it.

Create Table EMP1


(Empno Number,
Sal Number);

Create Or Replace Trigger EMP1


Before Insert On EMP1 For Each Row

Declare
V_Sal Number;

Begin

Select Sal INTO V_Sal


From EMP
Where Empno = :OLD.Empno;

Exception
When NO_DATA_FOUND Then
DBMS_OUTPUT.PUT_LINE('There is no salary for this employee in EMP Table');

End;

Insert Into EMP1 (Empno) Values(1003);

Message:
There is no salary for this employee in EMP Table

An Example For:
The Use Of Cursor In Database Triggers
Writing Cursor On The Trigger Table
Pulling Values From Another Table Into The Trigger Table

Drop Table EMP1;

Note:
Dropping a Table will not drop the trigger on it.

Thampy Mathew 165


Oracle Complete – A Quick Reference
PL/SQL
Create Table EMP1
(Empno Number,
Inserted Char(1));

Create Or Replace Trigger EMP1


Before Insert On EMP1 For Each Row

Declare
Cursor C1 Is Select Empno From Emp Order By Empno;
Cursor C2 Is Select Empno From Emp1 Order By Empno;
V_Empno Number;

Begin

For I In C1 Loop
:NEW.Empno := I.Empno;

For J In C2 Loop
If C2%FOUND Then
If I.Empno <> J.Empno Then
:NEW.Empno := I.Empno;
V_Empno := C2%ROWCOUNT;
End If;
Elsif C2%NOTFOUND Then
:NEW.Empno := I.Empno;
End If;
End Loop;

Exit When C1%ROWCOUNT > V_Empno And C1%ROWCOUNT > 0;


End Loop;

End;

Note:
If there is no record present in the cursor, the execution will not enter the loop.
Because of that the lines:
Elsif C2%NOTFOUND Then
:NEW.Empno := I.Empno;
will never get executed.

Insert Into EMP1 (Inserted) Values ('Y');


Insert Into EMP1 (Inserted) Values ('Y');
Insert Into EMP1 (Inserted) Values ('Y');
Insert Into EMP1 (Inserted) Values ('Y');

Thampy Mathew 166


Oracle Complete – A Quick Reference
PL/SQL
Select * From EMP1;

Output:
EMPNO INSERTED
----- -------------
7499 Y
7566 Y
7654 Y
7902 Y

User Defined Words to Replace the :NEW and :OLD


To use some other name of your choice instead of using :NEW and :OLD add the
following in the Trigger Creation syntax.

Create Or Replace Trigger PUR_NUM Before Insert Or Update Or Delete On


PUR_ORD Referencing Old As Existing New As Incoming For Each Row

In this trigger, for referencing existing and Incoming values you have to type :Existing
instead of :Old and :Incoming instead of :New.

Viewing the Trigger Text


Set Long 40000

Select Triiger_Name, Tigger_Type, Staus, Trigger_Body


From User(DBA)_Triggers
Where Tregger_Name Like ‘%xxx%’ ;

Instead Of Triggers
You can use INSTEAD OF triggers to tell Oracle what to do instead of performing the
action that invoked the trigger. For example, you could use an INSTEAD OF trigger on a
view to redirect inserts into a table or to update multiple tables that are part of a view.
You can use INSTEAD OF triggers on either object views or relational views.

For example, if a view involves a join of two tables, your ability to use the update
command on records in the view is limited. However, if use an INSTEAD OF trigger,
you can tell Oracle how to update, delete or insert records in the view’s underlying

Thampy Mathew 167


Oracle Complete – A Quick Reference
PL/SQL
tables when a user attempts to change values via the view. The code in the INSTEAD OF
trigger is executed in place of the insert, update or delete command you enter.

Syntax:

Create Or Replace Trigger <Trigger Name>


Instead Of Insert Or Delete Or Update On <Table/View Name>

Declare
<Variables>
Begin
<Code>
Exception
<Exception Handlers>
End;

OR

Create Or Replace Trigger <Trigger Name>


Instead Of Insert Or Delete Or Update of <Field1, Field2….Fieldn> On <Table/View
Name>

Declare
<Variables>
Begin
<Code>
Exception
<Exception Handlers>
End;

Schema Triggers or DDL Event Triggers

As of Oracle 8i, you can create triggers on Schema operations. The allowable triggering
vents include Create Table, Alter Table and Drop Table. You can even create triggers
to prevent users from dropping their own tables! For the most part, schema-level triggers
provide two capabilities: preventing DDL operations and providing additional security
monitoring when DDL operations occur.

Create Or Replace Trigger PREVENT_DROP


Before Drop On Scott.Schema

Begin

Thampy Mathew 168


Oracle Complete – A Quick Reference
PL/SQL
If Dictionary_Obj_Owner = ‘SCOTT’
And Dictionary_Obj_Name Like ‘EMP%’
And Dictionary_Obj_Type = ‘TABLE’ Then
RAISE_APPLICATION_ERROR (
-20002, ‘Operation not permitted.’);
End If;

End;

Mutating Errors
Mutating error occurs if you try to perform another DML operation in the trigger body. It
should be remembered that a database trigger fire along with a DML operation. A DML
operation locks the table. In other words when a trigger body fires the table will be in
locked position and in such a situation if you try to perform another DML operation on
the same table, it will end up in error and such an error is called mutating error.

But cursors can be written on the same trigger table because it is written at the
Declaration part of the trigger. The trigger table will get locked only after the Begin
statement.

What Is Not Possible


1. Triggers cannot be created on views.
2. Commit and Rollback is not possible in database triggers.
3. :NEW and :OLD key words cannot be used in Statement Level triggers.
4. In a trigger you cannot write to select a value from the same trigger table
5. Deletion of records from Master or Child tables of Master/Detail tables is not
possible through database triggers.

Disabling a Trigger
Alter Trigger <Trigger Name> Disable;
Alter Table <Table Name> Disable All Triggers;

Enabling a Trigger
Alter Trigger <Trigger Name> Enable;
Alter Table <Table Name> Enable All Triggers;

Thampy Mathew 169


Oracle Complete – A Quick Reference
PL/SQL
Dropping a Trigger
Drop Trigger <Trigger Name> ;

Procedures
Unnamed Procedures
Unnamed procedures are one or more PL/SQL blocks without an identity. These type of
procedures are not stored in the database and hence cannot be reused as and when
required.

Named Procedures
Named procedures are one or more PL/SQL blocks with a unique name as a identity.
These procedures are stored in the database and hence can be used any number of times
till then it is dropped.

Syntax:

Create Or Replace Procedure (Parameter1 IN Data type,


Parameter2 IN Data type,
---------------------------------------
Parameter n IN Data type,) AS
<Variables>

Begin
<Code>
Exception
<Exception Handlers>
End;

OR

Create Or Replace Procedure (Parameter1 OUT Data type,


Parameter2 OUT Data type,
---------------------------------------
Parameter n OUT Data type,) AS
<Variables>

Begin
<Code>
Exception
<Exception Handlers>
End;

Thampy Mathew 170


Oracle Complete – A Quick Reference
PL/SQL
OR

Create Or Replace Procedure (Parameter1 IN OUT Data type,


Parameter2 IN OUT Data type,
---------------------------------------
Parameter n IN OUT Data type,) AS
<Variables>
Begin
<Code>
Exception
<Exception Handlers>
End;

Caution:
Do not use the key word Declare before the first Begin statement in named
procedures. ‘Declare’ can be used if variables are defined inside the Begin
statement.

Example:

Create Table EMP1


(Empno Number,
Sal Number);

Procedure

Create Or Replace Procedure EMP1_Insert


(Empno IN Number, Sal IN Number) As

Begin
Insert Into EMP1 Values (Empno, Sal);
Commit;
End;

Execute EMP1_INSERT;

Select * From EMP1;

Output:
EMPNO SAL
----- ---------
1001 9000

Referencing Remote Tables In Procedures

Thampy Mathew 171


Oracle Complete – A Quick Reference
PL/SQL
Tables of another database can be accessed by SQL Statements in procedures via
database links.

Example:

Assumptions:
EMP is a table in DB1 Database
EMP1 is a table in DB2 database.
The database link between DB1 and DB2 is DB1_DB2

Create Or Replace Procedure EMP2_INSERT (V_Empno IN Number) IS


V_Ename Varchar2(20) ;

Begin

Select Ename INTO V_Ename From EMP Where Empno = V_Empno ;

Insert Into EMP1@DB1_DB2


(Ename) Values(V_Ename);

End;

Debugging Procedures

Syntax:

Show Error OR
Sho err

Detailed Information

The USER_ERRORS Table

DBA_ERRORS

Output:
Name Null? Type
----------------------- -------- ----
OWNER VARCHAR2(30) NOT NULL,
NAME VARCHAR2(30) NOT NULL,
TYPE VARCHAR2(12),
SEQUENCE NUMBER NOT NULL,
LINE NUMBER NOT NULL,

Thampy Mathew 172


Oracle Complete – A Quick Reference
PL/SQL
POSITION NUMBER NOT NULL,
TEXT VARCHAR2(4000) NOT NULL

Select Line, Position, Text


From USER_ERRORS
Where Name Like <NANE OF PROCEDURE/FUNCTION/PACKAGE in upper case>
And Type = 'PROCEDURE' / 'FUNCTION' / 'PACKAGE'
Order By Sequence;

Executing Named Procedures

Syntax:

Execute <Procedure Name>; OR


Exec <Procedure Name>;

IN, OUT Parameters in Procedures

IN Parameter

IN Parameters accepts values from the user

OUT Parameter

Example:

Declare
Mno Number;
Procedure Out_Proc (A OUT Number) IS

Begin
A := 7845610;
End;

Begin
Out_Proc (Mno);
DBMS_OUTPUT.PUT_LINE (Mno);
End;

Output: 7845610

Thampy Mathew 173


Oracle Complete – A Quick Reference
PL/SQL
IN OUT Parameter

Viewing The Text of a Named Procedure

The USER_SOURCE Table

DBA_SOURCE
Name Null? Type
--------------- -------- ----
OWNER VARCHAR2(30) NOT NULL,
NAME VARCHAR2(30) NOT NULL,
TYPE VARCHAR2(12)
LINE NUMBER NOT NULL
TEXT VARCHAR2(4000)

Select Text
From USER_SOURCE
Where Name Like <Name of PROCEDURE / FUNCTION / PACKAGE in upper case>
And Type = 'PROCEDURE' / 'FUNCTION' / 'PACKAGE'
Order By Line;

Dropping a Named Procedure

Drop Procedure <Procedure Name> ;

Using Procedures To Activate Triggers

Functions
Syntax:

Create Or Replace Function <Function Name>


(<Parameter1 Data type, Parameter1 Data type …….)
Return Number IS
<Variables>
Begin
<Code>
Exception
<Exception Handlers>

Thampy Mathew 174


Oracle Complete – A Quick Reference
PL/SQL
Return (<the value to be returned>);
End;

Caution:
Do not use the key word Declare before the first Begin statement in functions.
‘Declare’ can be used if variables are defined inside the Begin statement.

Function To Round a Figure With Another Base Other Than 0.50

Create Or Replace Function ROND (A Number)


Return Number IS

Begin
If (A – Floor (A)) >= 0.25 Then
Return Ceil (A);
Elsif (A – Floor (A)) < 0.25 Then
Return Floor (A);
End If;
End;

Select ROND (1254.356) From Dual;

Output: 1255

Function To Round That Accepts a Number, The Place of Rounding,


Round Base

Create Or Replace Function RUND


(A Number, B Number, C Number)
Return Number IS

D Number := 0;
E Number := 0;
F Number := 0;

Begin

If Sign (B) = 1 Then


D := A – Floor (A);

If TO_NUMBER (SUBSTR (D, (B + 2), 1)) >= C And C <> 0 Then


E := 1/ POWER (10, ABS (B));

Thampy Mathew 175


Oracle Complete – A Quick Reference
PL/SQL
D := TO_NUMBER (SUBSTR (D, 1, B + 1) + E);
F := FLOOR (A) + D;

Elsif TO_NUMBER (SUBSTR (D, (B + 2), 1)) < C And C <> 0 Then
F := (FLOOR (A) + (TO_NUMBER (SUBSTR (D, 1, B + 1))));

Elsif C = 0 Then
F := (FLOOR (A) + (TO_NUMBER (SUBSTR (D, 1, B + 1))));

End If;

End If;

If SIGN (B) = -1 Then


D := FLOOR(A);

If TO_NUMBER (SUBSTR (D, (LENGTH (D) + B + 1), 1))


>= C And C <> 0 Then
E := TO_NUMBER (SUBSTR (D, 1, (LENGTH (D) + B)));
F := (E + 1) * POWER (10, ABS (B));

Elsif TO_NUMBER (SUBSTR (D, (LENGTH (D) + B + 1), 1))


< C And C <> 0 Then
E := TO_NUMBER (SUBSTR (D, 1, (LENGTH (D) + B)));
F := E * POWER (10, ABS (B));

Elsif C = 0 Then
E := TO_NUMBER (SUBSTR (D, 1, (LENGTH (D) + B)));
F := E * POWER (10 , ABS (B));

End If;

End If;

Return (F);

End;

Select RUND (124.456789, 3, 8) From Dual;

Output: 124.456

Explanation:

Thampy Mathew 176


Oracle Complete – A Quick Reference
PL/SQL
The Number to Round : 124.456789
Rounding Position :3
Round Base :8

Increase the rounding position value by 1 if the value in the next position is more than the
user specified round base and discard the rest of the digits, else discard all the digits
ahead of the rounding position specified by the user.

Function To Pad On the Left Side of a String For a User Specified


Length With a Specified Character

Create Or Replace Function Leftpad


(A Varchar2, B Number, C Varchar2)
Return Varchar2 IS

D Varchar2(50) := C;

Begin

For I In 1.. (B - (LENGTH (A) + 1)) Loop


D := D||C;
End Loop;

Return (A||D);

End;

Function To Pad On the Right Side of a String For a User Specified


Length With a Specified Character

Create Or Replace Function Rightpad


(A Varchar2, B Number, C Varchar2)
Return Varchar2 IS

D Varchar2(50) := C;
Begin

For I In 1.. (B - (LENGTH (A) + 1)) Loop


D := D||C;
End Loop;

Return (A||D);

Thampy Mathew 177


Oracle Complete – A Quick Reference
PL/SQL
End;

Function To Find Power of a Number

Create Or Replace Function POVER


(A Number, B Number) Return Number IS

C Number := A;

Begin

For I In 1.. (B – 1) Loop


C := C * A;
End Loop;

Return (C);

End;

Function To Find The Square Root of a Number

Create Or Replace Function ROOT


(A Number, B Number) Return Number IS

C Number;
I Number := 0.001;

Begin
While POVER (I, B) <= ( A + 0.005) Loop
C := I;
I := I + 0.001;
End Loop;

Return(C);

End;

Function To Check Whether An Input Number Is Prime

A prime number is number that cannot be divided by any number other than 1 or itself.

Thampy Mathew 178


Oracle Complete – A Quick Reference
PL/SQL
Create Or Replace Function PRIME_NUM (P Number) Return Number IS
B Varchar2(50);

Begin

For I In 2 .. (P - 1) Loop
If MOD (P, I) = 0 Then
B := 'The Number Is Not Prime';
Exit;
Elsif MOD (P, I) > 0 Then
B := 'The Number Is Prime';
End If;
End Loop;
End;

Function To Reverse a String

Create Or Replace Function REVERSE_STRING (A Varchar2) Return Varchar2 IS


B Number;
C Varchar2(10);
D Varchar2(10);

Begin

B := LENGTH (A);

For I In 1..B Loop


C := SUBSTR (A, B, 1);
B := B - 1;
D := D||C;
End Loop;

Return (D);

End;

Function To Find The Factorial of a Number

The factorial of a number n, written as n!, is the product of the consecutive integers 1
thorough n. For example 5! = 1 x 2 x 3 x 4 x 5 = 120

Create Or Replace Function FACTORIAL (A Number)

Thampy Mathew 179


Oracle Complete – A Quick Reference
PL/SQL
Return Number IS
B Number := 1;

Begin

For I In 1.. A Loop


B := B * I;
End Loop;

Return (B);

End;

Function to Find the nth Triangular Number

*
* *
* * *
* * * *
* * * * *

15 dots arranged in a triangular shape (5 rows). The number of rows it would take to form
a triangle containing n rows would be the sum of the integers from 1 to n. This sum is
known as a triangular number. If we start at 1 the 4 th triangular number is (1+2+3+4 =
10)

Create Or Replace Function TRIANGULAR_NO (A Number)


Return Number IS
B Number := 0;

Begin

For I In 1.. A Loop


B := B + I;
End Loop;

Return (B);

End;

A More Efficient Function For nth Triangular Number

Thampy Mathew 180


Oracle Complete – A Quick Reference
PL/SQL
Create Or Replace Function TRIANGULAR_NO (A Number)
Return Number IS
B Number := 0;

Begin

B := A (A + 1) / 2 ; /* nth triangular number = n (n + 1) / 2 */

Return (B);
End;

As the loop is removed the execution will be much faster.

Viewing the Text of a Defined Function

Select Text
From USER_SOURCE
Where Name Like <Name of PROCEDURE / FUNCTION / PACKAGE in upper case>
And Type = 'PROCEDURE' / 'FUNCTION' / 'PACKAGE'
Order By Line;

Dropping a Function

Drop Function <Function Name>;

Exception Handling
All errors are having a code and a few of them have predefined names also.

Pre-defined Errors Names and their Codes

Name Code

1. CURSOR_ALREADY_OPEN ---------- ORA-06511


2. DUP_VAL_ON_INDEX ----------------- ORA-00001
3. INVALID_CURSOR ---------------------- ORA-01001
4. LOGIN_DENIED ------------------------- ORA-01017
5. NO_DATA_FOUND --------------------- ORA-01403
6. NOT_LOGGED_IN ---------------------- ORA-01012
7. PROGRAM_ERROR --------------------- ORA-06501
8. STORAGE_ERROR ---------------------- ORA-06500

Thampy Mathew 181


Oracle Complete – A Quick Reference
PL/SQL
9. TIME_OUT_ON_RESUME -------------- ORA-00051
10. TOO_MANY_ROWS --------------------- ORA-01422
11. TRANSACTION_BACKED_OUT ----- ORA-00061
12. VALUE_ERROR -------------------------- ORA-06502
13. ZERO_DIVIDE ---------------------------- ORA-01476
14. INVALID_NUMBER --------------------- ORA-01722
15. OTHERS ------------------------------------ Used to name any code

Few Other Codes

ORA-01400 Mandatory Not Null column missing


ORA-01401 Cannot update Not Null column to Null
ORA-04088 Error during execution of trigger
ORA-04092 Trigger may not Commit and Rollback
ORA-02291 Violated integrity constraint – child record found
ORA-02290 Violated check constraint

Example:

Declare
V_Sal Number;

Begin

Select Sal Into V_Sal From EMP Where HIREDATE = ’10-12-99’;


DBMS_OUTPUT.PUT_LINE (V_Sal) ;

Exception
When OTHERS Then
DBMS_OUTPUT.PUT_LINE (‘Date format is incorrect’) ;

End;

Output: Date format is incorrect

Note:
OTHERS is an error code that can be used as a name for any error. When the
correct error code is not known, you can use OTHERS to trap any error.

User Defined Error Names With Pragma Exceptions


User can define names for errors without code and PRAGMA EXCEPTION_INIT ca be
used to connect the name with the error_code as shown below.

Thampy Mathew 182


Oracle Complete – A Quick Reference
PL/SQL
Declare

Invalid_Month Exception;
Pragma Exception_Init (Invalid_Month, -1843);
V_Sal Number;

Begin

Select Sal Into V_Sal From EMP Where HIREDATE = ’10-12-99’;


DBMS_OUTPUT.PUT_LINE (V_Sal) ;

Exception
When Invalid_Month Then
DBMS_OUTPUT.PUT_LINE (‘Date format is incorrect’) ;

End;

Output: Date format is incorrect

User Defined Error Names With RAISE_APPLICATION_ERROR


Create Or Replace Trigger EMP1_INSERT
Before Insert On EMP1 For Each Row

Invalid_Month Exception;
Not_Null_Column_Missing Exception;
V_Sal Number;

Begin

Select Sal Into V_Sal From EMP Where HIREDATE = ’10-12-99’;


RAISE Invalid_Month;
Insert Into EMP1 (Sal) Values (V_Sal) ;
RAISE Not_Null_Column_Missing ;

Exception
When Invalid_Month Then
RAISE_APPLICATION_ERROR (-1843, ‘Date format is incorrect’) ;

When Not_Null_Column_Missing Then


RAISE_APPLICATION_ERROR (-01400, ‘Not null column missing’) ;

End;

Thampy Mathew 183


Oracle Complete – A Quick Reference
PL/SQL

Packages
A Package can be assumed as a bag to group procedures and functions. A package has
two parts viz. Package Specification and Package Body.

Package Specification
The Package Specification lists the procedures and functions included in the Package
Body. You cannot create a procedure or function in the package body without listing it in
the Package Specification.

Syntax

Create Or Replace Package <Package Name> AS


Procedure <Procedure Name 1 along with the parameters> ;
Procedure <Procedure Name 2 along with the parameters> ;
Procedure <Procedure Name 3 along with the parameters> ;
Function <Function Name 1 along with the parameters> Retun <Data type> ;
Function <Function Name 1 along with the parameters> Retun <Data type> ;
End;

Package Body
The Package Body consists of the functions and procedures listed in the Package
Specification.

Syntax:

Create Or Replace Package Body <Package Name> AS

<Procedure Name> /* Do not write Create Or Replace here */


The remaining part of the procedure

<Function Name> /* Do not write Create Or Replace here */


The remaining part of the function
End <Package Name> ;

Thampy Mathew 184


Oracle Complete – A Quick Reference
PL/SQL
Example:

Package Specification

Create Or Replace Package MY_COLLECTION AS

Function EMP_Empno (V_Ename Varchar2) Return Number ;

Procedure LEFTPAD (A Varchar2, B Number, C Varchar2) ;

Procedure RIGHTPAD (A Varchar2, B Number, C Varchar2) ;

End MY_COLLECTION;

Note:
The function and procedure names can be repeated inside and outside a package.

Package Body

Create Or Replace Package Body MY_COLLECTION AS

Function EMP_Empno (V_Ename Varchar2) Return Number IS


V_Empno Number;

Begin

Select Empno INTO V_Empno From EMP Where Ename = V_Ename;


Return (V_Empno);

End EMP_Empno;

Procedure ROND (A Number) IS

Begin

If (A - FLOOR (A)) >= 0.25 Then


DBMS_OUTPUT.PUT_LINE(Ceil (A));
Elsif (A - FLOOR (A)) < 0.25 Then
DBMS_OUTPUT.PUT_LINE (FLOOR (A));
End If;

End ROND;

Thampy Mathew 185


Oracle Complete – A Quick Reference
PL/SQL
--Procedure To Pad On the Left Side of a String For a User Specified Length With a
--Specified Character

Procedure LEFTPAD (A Varchar2, B Number, C Varchar2) IS


D Varchar2(50) := C;

Begin

For I In 1.. (B - (LENGTH (A) + 1)) Loop


D := D||C;
End Loop;
DBMS_OUTPUT.PUT_LINE(A||D);

End LEFTPAD;

--Procedure To Pad On the Right Side of a String For a User Specified Length With a
--Specified Character

Procedure RIGHTPAD (A Varchar2, B Number, C Varchar2) IS


D Varchar2(50) := C;

Begin

For I In 1.. (B - (LENGTH (A) + 1)) Loop


D := D||C;
End Loop;
DBMS_OUTPUT.PUT_LINE(A||D);

End RIGHTPAD;

End MY_COLLECTION;

Package Execution

Exec <Package Name>.<Procedure Name with Parameters>

Select <Package Name>.<Function Name with Parameters> From <table name for which
the function is created> ;

Executing All The Functions And Procedures In a Package In One Command

Thampy Mathew 186


Oracle Complete – A Quick Reference
PL/SQL
Write a separate procedure for the execution and include that in the Package.

Dropping a Package

Drop Package <Package Name> ;

Dropping a Package Body

Drop Package Body <Package Name> ;

Thampy Mathew 187


Oracle Complete – A Quick Reference
PL/SQL

Dynamic SQL
Dynamic SQL uses the package DBMS_SQL. The statement for DBMS_SQL is different
depending upon the type as follows.

1. Non-query DDL and DML


(CREATE, DROP TRUNCATE; INSERT, UPDATE, DELETE)

Steps:
1. Open Cursor
2. Create the DDL/DML statement as character string
3. Parse the statement
4. Assign values to Bind variables (if required)
5. Execute the statement
6. Close the cursor

2. Query (SELECT)

Steps:
1. Open Cursor
2. Create the SELECT statement as character string
3. Parse the statement
4. Define names of output columns (with length for Varchar2 columns)
(DEFINE_COLUMN)
5. Execute the statement
6. Loop for the fetched rows
7. Capture values into the output column names defined in step 4
(COLUMN_VALUE)
8. Close the cursor

3. Anonymous PL/SQL blocks

Thampy Mathew 188


Oracle Complete – A Quick Reference
PL/SQL
1. Non-query DDL and DML
(CREATE, DROP TRUNCATE; INSERT, UPDATE, DELETE)

Example for Table Creation

Declare
V_CID INTEGER;
V_CREATE_SMT VARCHA2(4000);
V_NUMROWS INTEGER;

Begin
V_CID := DBMS_SQL.OPEN_CURSOR;

V_CREATE_SMT := ‘CREATE TABLE MYTABLE


(MYTABLE_ID NUMBER PRIMARY KEY,
NAME VARCHAR2(50),
ADDRESS VARCHAR2(240))’;

DBMS_SQL.PARSE(V_CID, V_CREATE_SMT, DBMS_SQL.V7);

V_NUMROWS := DBMS_SQL.EXECUTE(V_CID);

EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(‘Table already exists’);

DBMS_SQL.CLOSE_CURSOR(V_CID);

End;

Example for Inserting Records into a Table

Declare
V_CID INTEGER;
V_INSERT_SMT VARCHA2(4000);
V_NUMROWS INTEGER;

Begin
V_CID := DBMS_SQL.OPEN_CURSOR;

V_INSERT_SMT := ‘INSERT INTO MYTABLE


(MYTABLE_ID,

Thampy Mathew 189


Oracle Complete – A Quick Reference
PL/SQL
NAME,
ADDRESS)
VALUES
(:MYTABLE_ID,
:NAME,
:ADDRESS)’;

DBMS_SQL.PARSE(V_CID, V_INSERT_SMT, DBMS_SQL.V7);

-- Inserting first record

DBMS_SQL.BIND_VARIABLE(V_CID, ‘:MYTABLE_ID’, 1);


DBMS_SQL.BIND_VARIABLE(V_CID, ‘:NAME’, ‘THAMPY’);
DBMS_SQL.BIND_VARIABLE(V_CID, ‘:ADDRESS’, ‘MUMBAI’);

V_NUMROWS := DBMS_SQL.EXECUTE(V_CID);

-- Inserting second record

DBMS_SQL.BIND_VARIABLE(V_CID, ‘:MYTABLE_ID’, 2);


DBMS_SQL.BIND_VARIABLE(V_CID, ‘:NAME’, ‘MATHEW’);
DBMS_SQL.BIND_VARIABLE(V_CID, ‘:ADDRESS’, ‘HYDERABAD’);

V_NUMROWS := DBMS_SQL.EXECUTE(V_CID);

EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(‘Unique constraint violated’);

DBMS_SQL.CLOSE_CURSOR(V_CID);

COMMIT;

End;

Note:
1. If a field name is captured in a variable, it can be concatenated in the INSERT
statement string.

2. While assigning values to BIND_VARIABLES, you can use variables instead of


hard-corded values.

Thampy Mathew 190


Oracle Complete – A Quick Reference
PL/SQL

2. Query (SELECT)

Example for Selecting Records from a Table

Declare
V_CID INTEGER;
V_SELECT_SMT VARCHA2(4000);
V_NUMROWS INTEGER;
--
V_MYTABLE_ID INTEGER;
V_NAME VARCHAR2(50);
V_ADDRESS VARCHAR2(240);

Begin
V_CID := DBMS_SQL.OPEN_CURSOR;

V_ SELECT_SMT := ‘SELECT
MYTABLE_ID,
NAME,
ADDRESS
FROM
MYTABLE’;

DBMS_SQL.PARSE(V_CID, V_SELECT_SMT, DBMS_SQL.V7);

-- Assigning column serial order and variable name to which the column value is
-- is to be captured

DBMS_SQL.DEFINE_COLUMN(V_CID, 1, V_MYTABLE_ID);
DBMS_SQL.DEFINE_COLUMN(V_CID, 2, V_NAME, 50);
DBMS_SQL. DEFINE_COLUMN (V_CID, 3, V_ADDRESS, 240);
(Note that field width is assigned for character fields)

V_NUMROWS := DBMS_SQL.EXECUTE(V_CID);

LOOP

IF DBMS_SQL.FETCH_ROWS(V_CID) = 0 THEN
EXIT;
END IF;

-- Capturing column values

Thampy Mathew 191


Oracle Complete – A Quick Reference
PL/SQL
DBMS_SQL.COLUMN_VALUE(V_CID, 1, V_MYTABLE_ID);
DBMS_SQL.BIND_VARIABLE(V_CID, 2, V_NAME);
DBMS_SQL.BIND_VARIABLE(V_CID, 3, V_ADDRESS);

END LOOP;

EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(‘XXXX’);

DBMS_SQL.CLOSE_CURSOR(V_CID);

End;

3. Anonymous PL/SQL Blocks

Example Dynamiv PL/SQL Block

Declare
V_CID INTEGER;
V_BLOCK_SMT VARCHA2(4000);
V_NUMROWS INTEGER;
--
V_MYTABLE_ID INTEGER;
V_NAME VARCHAR2(50);

Begin
V_CID := DBMS_SQL.OPEN_CURSOR;

V_BLOCK_SMT := ‘BEGIN
SELECT
MYTABLE_ID, NAME
INTO :MYTABLE_ID, :NAME
FROM
MYTABLE
WHERE NAME = ‘THAMPY’;
END;’;

DBMS_SQL.PARSE(V_CID, V_BLOCK_SMT, DBMS_SQL.V7);

-- Assigning variables against each BIND VARIABLE

DBMS_SQL.BIND_VARIABLE(V_CID, ‘:MYTABLE_ID’, V_MYTABLE_ID);

Thampy Mathew 192


Oracle Complete – A Quick Reference
PL/SQL
DBMS_SQL.BIND_VARIABLE(V_CID, ‘:NAME’, V_NAME);

V_NUMROWS := DBMS_SQL.EXECUTE(V_CID);

-- Transferring BIND VARIABLE values to variables

DBMS_SQL.VARIABLE_VALUE(V_CID, ‘:MYTABLE_ID’, V_MYTABLE_ID);


DBMS_SQL.VARIABLE_VALUE(V_CID, ‘:NAME’, V_NAME);

DBMS_OUPUT.PUT_LINE(V_MYTABLE_ID||’ ‘||V_NAME);

EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(‘ERROR’);

DBMS_SQL.CLOSE_CURSOR(V_CID);

COMMIT;

End;

Example for Combined Use of Different Types of DBMS_SQL

This example is based on the following requirements.

1. Create the table TEMP(SLNO NUMBER PRIMARY KEY,


COL1 NUMBER,
COL2 NUMBER,
CALC_VALUE NUMBER)

2. Create another table FORMULAS(SLNO NUMBER PRIMARY KEY,


FORMULA(VARCHAR2(100))

3. Insert one record into TEMP(SLNO, COL1, COL2)


VALUES(1, 10, 5)

4. Insert one record into FORMULS(SLNO, FORMULA)


VALUES(1, ‘COL1*COL2’)

5. Pick the formula string into a variable from the FORMULAS table, derive the
value of the formula from the TEMP table by passing the variable that contains
the formula string and update the TEMP table (CALC_VALUE field) with the
derived formula value.

Thampy Mathew 193


Oracle Complete – A Quick Reference
PL/SQL
-- Creating table
--
DECLARE
V_CID1 INTEGER;
V_CREATE_STMT VARCHAR2(1000);
V_NUMROWS INTEGER;

BEGIN
--
V_CID1 := DBMS_SQL.OPEN_CURSOR;
V_CREATE_STMT := 'CREATE TABLE TEMP
(SLNO NUMBER PRIMARY KEY,
COL1 NUMBER,
COL2 NUMBER,
CALC_VALUE NUMBER)';

DBMS_SQL.PARSE(V_CID1, V_CREATE_STMT, DBMS_SQL.V7);

V_NUMROWS := DBMS_SQL.EXECUTE(V_CID1);

DBMS_SQL.CLOSE_CURSOR(V_CID1);
--
-- Creating another table with the same variables
--
V_CID1 := DBMS_SQL.OPEN_CURSOR;
V_CREATE_STMT := 'CREATE TABLE FORMULAS
(SLNO NUMBER PRIMARY KEY,
FORMULA VARCHAR2(100))';

DBMS_SQL.PARSE(V_CID1, V_CREATE_STMT, DBMS_SQL.V7);

V_NUMROWS := DBMS_SQL.EXECUTE(V_CID1);

DBMS_SQL.CLOSE_CURSOR(V_CID1);

END;
/
--
-- The CREATE table block is separated as otherwise the PARSE statements of SELECT,
-- INSERT, UPDATE etc. in the block gives error as the tables are not existing
--
DECLARE
V_CID2 INTEGER;
V_CID3 INTEGER;
V_CID4 INTEGER;

Thampy Mathew 194


Oracle Complete – A Quick Reference
PL/SQL
V_CID5 INTEGER;
V_CID6 INTEGER;
--
V_INSERT_STMT VARCHAR2(1000);
V_SELECT_STMT VARCHAR2(1000);
V_UPDATE_STMT VARCHAR2(1000);
V_COMMIT_STMT VARCHAR2(1000);
--
V_NUMROWS INTEGER;
--
V_FORMULA VARCHAR2(100);
V_FORMULA_VALUE INTEGER;

BEGIN
--
-- Inserting records into a table
--
V_CID2 := DBMS_SQL.OPEN_CURSOR;

V_INSERT_STMT := 'INSERT INTO TEMP(SLNO, COL1,COL2)


VALUES(:SLNO, :COL1, :COL2)';

DBMS_SQL.PARSE(V_CID2, V_INSERT_STMT, DBMS_SQL.V7);

DBMS_SQL.BIND_VARIABLE(V_CID2, ':SLNO', 1);


DBMS_SQL.BIND_VARIABLE(V_CID2, ':COL1', 10);
DBMS_SQL.BIND_VARIABLE(V_CID2, ':COL2', 5);

V_NUMROWS := DBMS_SQL.EXECUTE(V_CID2);

DBMS_SQL.CLOSE_CURSOR(V_CID2);
--
-- Inserting records into a another table using the same variables
--
V_CID2 := DBMS_SQL.OPEN_CURSOR;

V_INSERT_STMT := 'INSERT INTO FORMULAS(SLNO, FORMULA)


VALUES(:SLNO, :FORMULA)';
DBMS_SQL.PARSE(V_CID2, V_INSERT_STMT, DBMS_SQL.V7);

DBMS_SQL.BIND_VARIABLE(V_CID2, ':SLNO', 1);


DBMS_SQL.BIND_VARIABLE(V_CID2, ':FORMULA', 'COL1*COL2');

V_NUMROWS := DBMS_SQL.EXECUTE(V_CID2);

DBMS_SQL.CLOSE_CURSOR(V_CID2);

Thampy Mathew 195


Oracle Complete – A Quick Reference
PL/SQL
--
-- Selecting a Formula into a variable as character string
--
SELECT FORMULA INTO V_FORMULA FROM FORMULAS;
--
-- Passing the character string of the formula captured in a variable to a select statement
-- and getting the value of the formula
--
V_CID3 := DBMS_SQL.OPEN_CURSOR;

V_SELECT_STMT := 'SELECT '||V_FORMULA||' FROM TEMP';

DBMS_SQL.PARSE(V_CID3, V_SELECT_STMT, DBMS_SQL.V7);

DBMS_SQL.DEFINE_COLUMN(V_CID3, 1, V_FORMULA_VALUE);

V_NUMROWS := DBMS_SQL.EXECUTE(V_CID3);

LOOP

IF DBMS_SQL.FETCH_ROWS(V_CID3) = 0 THEN
EXIT;
END IF;

DBMS_SQL.COLUMN_VALUE(V_CID3, 1, V_FORMULA_VALUE);

DBMS_OUTPUT.PUT_LINE(TO_CHAR(V_FORMULA_VALUE));
--
-- Updating a column with the derived formula value
--
V_CID4 := DBMS_SQL.OPEN_CURSOR;

V_UPDATE_STMT := 'UPDATE TEMP SET CALC_VALUE = :CALC_VALUE';

DBMS_SQL.PARSE(V_CID4, V_UPDATE_STMT, DBMS_SQL.V7);

DBMS_SQL.BIND_VARIABLE(V_CID4, ':CALC_VALUE', V_FORMULA_VALUE);

V_NUMROWS := DBMS_SQL.EXECUTE(V_CID4);

DBMS_SQL.CLOSE_CURSOR(V_CID4);

END LOOP;

DBMS_SQL.CLOSE_CURSOR(V_CID3);
--

Thampy Mathew 196


Oracle Complete – A Quick Reference
PL/SQL
-- Commiting
--
V_CID5 := DBMS_SQL.OPEN_CURSOR;

V_COMMIT_STMT := 'COMMIT';

DBMS_SQL.PARSE(V_CID5, V_COMMIT_STMT, DBMS_SQL.V7);

V_NUMROWS := DBMS_SQL.EXECUTE(V_CID5);

DBMS_SQL.CLOSE_CURSOR(V_CID5);
--
-- For COMMIT no dynamic SQL is required as shown above. It can be a simple
-- COMMIT statement as PL/SQL blocks accept it.
--
END;
/

Thampy Mathew 197

You might also like