Professional Documents
Culture Documents
PL/SQL stands for Procedural Language/SQL.PL/SQL extends SQL by adding control Structures found in other
procedural language.PL/SQL combines the flexibility of SQL with Powerful feature of 3rd generation Language.
The procedural construct and database access Are present in PL/SQL.PL/SQL can be used in both in database
in Oracle Server and in Client side application development tools.
Advantages of PL/SQL
Support for SQL, support for object-oriented programming,, better performance, portability, higher
productivity, Integration with Oracle
a] Supports the declaration and manipulation of object types and collections.
b] Allows the calling of external functions and procedures.
c] Contains new libraries of built in packages.
d] with PL/SQL , an multiple sql statements can be processed in a single command line statement.
Oracle Supports PL/SQL version 8.0.4.0.0
PL/SQL Datatypes
Scalar Types
BINARY_INTEGER ,DEC,DECIMAL,DOUBLE ,,PRECISION,FLOAT,INT,INTEGER,NATURAL, NATURALN,NUMBER,
NUMERIC, PLS_INTEGER,POSITIVE,POSITIVEN,REAL,SIGNTYPE, SMALLINT,CHAR,CHARACTER,LONG,LONG
RAW,NCHAR,NVARCHAR2,RAW,ROWID,STRING, VARCHAR,VARCHAR2,
Composite Types
TABLE, VARRAY, RECORD
LOB Types
BFILE, BLOB, CLOB, NCLOB
Reference Types
REF CURSOR
BOOLEAN, DATE
DBMS_OUTPUT.PUT_LINE :
It is a pre-defined package that prints the message inside the parenthesis
ATTRIBUTES
Allow us to refer to data types and objects from the database.PL/SQL variables and Constants can have
attributes. The main advantage of using Attributes is even if you Change the data definition, you dont need
to change in the application.
%TYPE
It is used when declaring variables that refer to the database columns.
Using %TYPE to declare variable has two advantages. First, you need not know the exact datatype of
variable. Second, if the database definition of variable changes, the datatype of variable
changes
accordingly at run time.
%ROWTYPE
The %ROWTYPE attribute provides a record type that represents a row in a table (or view). The record can
store an entire row of data selected from the table or fetched from a cursor or strongly typed cursor
variable.
CONTROL STRUCTURES
Conditional Control
Sequence of statements can be executed based on a certain condition using the if statement.There are three
forms of if statements, namely, if then,if then else and if the Elsif.
ITERATIVE CONTROL
A sequence of statements can be executed any number of times using loop constructs.
Loops can be broadly classified into:
Simple Loops , For Loops , While Loops
Simple Loops
Key Word loop should be placed before the first statement in the sequence and the key word end loop after
the last statement in the sequence.
EXIT : It is a command that comes out of the loop.
While Loop
This statement includes a condition associated with a sequence of statement. If the Condition evaluates to
true, then the sequence of statements will be executed, and again Control resumes at the beginning of the
loop else the loop is bypassed and control passes To next statement.
For Loop
The number of iterations for a while loop is unknown until the loop terminates, whereas The number of
iterations in a for loop is known before the loop gets executed. The for loop statement specifies a range of
integers, to execute the sequence of statements once for each integer.
REVERSE: Reverse key word is used to print the values from upper bound to lower bound.
EXCEPTION
An Exception is raised when an error occurs. In case of an error then normal execution stops and the control
is immediately transferred to the exception handling part of the PL/SQL Block.
Exceptions are designed for runtime handling, rather than compile time handling. Exceptions improve
readability by letting you isolate error-handling routines.
Types
Pre-defined Exception, User-defined Exception
USER DEFINED EXCEPTIONS
User defined exception must be defined and explicitly raised by the user
EXCEPTION_INIT
A named exception can be associated with a particular oracle error. This can be used to trap the error
specifically.
PRAGMA EXCEPTION_INIT(exception_name, Oracle_error_number);
The pragma EXCEPTION_INIT associates an exception name with an Oracle,error number. That allows you to
refer to any internal exception by name and to write a specific handler
RAISE_APPLICATION_ERROR
The procedure raise_application_error lets you issue user-defined error messages from stored subprograms.
That way, you can report errors to your application and avoid returning unhandled exceptions.
To call raise_application_error, you use the syntax
raise_application_error(error_number, message[, {TRUE | FALSE}]);
2
where error_number is a negative integer in the range -20000 .. -20999 and message is a character string
up to 2048 bytes long.
PRE DEFINED EXCEPTIONS
Merits
1] Allowing to position at specific rows of the result set.
2] Returning one row or block of rows from the current position in the result set.
3] Supporting data modification to the rows at the current position in the result set.
TYPES
1] STATIC CURSOR
SQL statement is determined at design time.
A] EXPLICIT
EXPLICIT CURSOR --
Usage - If the SELECT statement returns more that one row then explicit cursor should be used.
Steps
Declare a cursor
Open a cursor
Fetch data from the cursor
Close the cursor
Syntax
CURSOR <CURSOR NAME> IS <SELECT STATEMENT>
OPEN <CURSOR NAME>
FETCH <CURSOR NAME> INTO <COLUMN NAMES>
CLOSE <CURSOR NAME>
EXPLICIT CURSOR ATTRIBUTES
%FOUND (Returns true if the cursor has a value)
%NOTFOUND (Returns true if the cursor does not contain any value)
%ROWCOUNT (Returns the number of rows selected by the cursor)
%ISOPEN (Returns the cursor is opened or not)
CURSOR FOR LOOPS
A cursor FOR loop implicitly opens a cursor, fetches the rows and closes the cursor automatically.
SYNTAX
FOR <RECORD NAME> IN <CURSOR NAME> LOOP
STATEMENTS
END LOOP;
To refer an element of the record use <record name.column name>
EXPLICIT CURSOR WITH FOR LOOP
DECLARE
CURSOR C1 IS SELECT EMPNO,ENAME,SAL FROM EMP;
BEGIN
FOR ROW1 IN C1
LOOP
DBMS_OUTPUT.PUT_LINE(ROW1.EMPNO);
DBMS_OUTPUT.PUT_LINE(ROW1.ENAME);
END LOOP;
END;
EXPLICIT CURSOR
BEGIN
FOR ROW1 IN (SELECT EMPNO,ENAME,SAL FROM EMP)
LOOP
DBMS_OUTPUT.PUT_LINE(ROW1.EMPNO);
DBMS_OUTPUT.PUT_LINE(ROW1.ENAME);
END LOOP;
END;
EXPLICIT CURSOR ROW POSITIONING
DECLARE
CURSOR C1 IS SELECT EMPNO,ENAME,SAL,DEPTNO FROM EMP ORDER BY sal;
ENO EMP.EMPNO%TYPE;
EMPNAME EMP.ENAME%TYPE;
SAL1 EMP.SAL%TYPE;
DNO EMP.DEPTNO%TYPE;
BEGIN
OPEN C1;
LOOP
EXIT WHEN C1%ROWCOUNT=5 OR C1%NOTFOUND;
FETCH C1 INTO ENO,EMPNAME,SAL1,DNO;
DBMS_OUTPUT.PUT_LINE('EMPNO ' || ENO ||' EMPNAME ' || EMPNAME ||'
INSERT INTO EMP51 VALUES(ENO,EMPNAME,SAL1,DNO);
COMMIT;
SALARY
' || SAL1);
END LOOP;
CLOSE C1;
END;
B ] IMPLICIT CURSOR
An IMPLICIT cursor is associated with any SQL DML statement that does not have a explicit cursor
associated with it.
This includes :
"
All INSERT statements
"
All UPDATE statements
"
All DELETE statements
IMPLICIT CURSOR ATTRIBUTES
"
SQL%FOUND (Returns true if the DML operation is valid)
"
SQL%NOTFOUND (Returns true if the DML operation is invalid)
"
SQL%ROWCOUNT (Returns the no. of rows affected by the DML operation)
SQL%FOUND - IMPLICIT
BEGIN
UPDATE EMP51 SET SAL=SAL+50.50 WHERE DEPTNO=&Department_No;
IF SQL%NOTFOUND THEN
DBMS_OUTPUT.PUT_LINE('Invalid Salary Updation' );
ELSif SQL%FOUND THEN
DBMS_OUTPUT.PUT_LINE('Sucessfully Updated' );
END IF;
END;
SQL%ROWCOUNT - IMPLICIT
BEGIN
END;
BEGIN
END;
DNO EMP.DEPTNO%TYPE:=&DEPT_NO;
ENO EMP.EMPNO%TYPE;
ENAME1 EMP.ENAME%TYPE;
ESAL EMP.SAL%TYPE;
CURSOR C1 IS SELECT EMPNO,ENAME,SAL FROM EMP WHERE DEPTNO=DNO;
OPEN C1;
LOOP
FETCH C1 INTO ENO,ENAME1,ESAL;
EXIT WHEN C1%NOTFOUND;
IF ESAL<1200 THEN
UPDATE EMP SET COMM=SAL*.6 WHERE DEPTNO=DNO AND (SAL<1200);
ELSIF ESAL>1200 AND ESAL<=1500 THEN
UPDATE EMP SET COMM=SAL*.4 WHERE DEPTNO=DNO AND (SAL>1200 AND SAL<=1500);
ELSE
UPDATE EMP SET COMM=SAL*.5 WHERE DEPTNO=DNO AND (SAL>1500);
END IF;
DBMS_OUTPUT.PUT_LINE(ENO);
DBMS_OUTPUT.PUT_LINE(ENAME1);
END LOOP;
COMMIT;
DBMS_OUTPUT.PUT_LINE(C1%ROWCOUNT);
CLOSE C1;
2 ]DYNAMIC CURSOR
Dynamic Cursor can be used along with DBMS_SQL package .A SQL statement is dynamic, if it is constructed
at run time and then executed.
3 ] REF CURSOR
Declaring a cursor variable creates a pointer, not an item. In PL/SQL, a pointer has datatype REF X, where
REF is short for REFERENCE and X stands for a class of objects. Therefore, a cursor variable has datatype
REF CURSOR.
To execute a multi-row query, Oracle opens an unnamed work area that stores
processing information. To access the information, you can use an explicit cursor, which
names the work area. Or, you can use a cursor variable, which points to the work area.
Mainly, you use cursor variables to pass query result sets between PL/SQL stored subprograms and various
clients. Neither PL/SQL nor any of its clients owns a result set; they simply share a pointer to the query work
area in which the result set is stored. For example, an OCI client, Oracle Forms application, and Oracle
Server can all refer to the same work area.
a] Strong Cursor - Whose return type specified.
b] Week Cursor - Whose return type not specified.
Ref Cursor
Ref are the best way of uniqely referring to object instances.It is only supported way of getting at OID
( object identifier ).It is a effecient and light means of passing object information as a information
Dref
It is the 'deference operator.Like VALUE,it return the value of an object,Unlike value.
Dref's input is a REF to an column in a table and you want reterive the target instead of the pointer,you
DREF.
REF CURSOR - 1
DECLARE
TYPE RE1 IS REF CURSOR;
A RE1;
B RE1;
A1 NUMBER;
B1 VARCHAR2(20);
C1 VARCHAR2(20);
BEGIN
OPEN A FOR SELECT EMPNO,ENAME,JOB FROM EMP;
LOOP
FETCH A INTO A1,B1,C1;
EXIT WHEN A%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(A1||' '||B1||'
END LOOP;
CLOSE A;
END;
/
'||C1);
REF CURSOR - 2
CREATE OR REPLACE PROCEDURE PREF2 IS
TYPE RE1 IS REF CURSOR;
SQL_STMT RE1;
A1 NUMBER;
B1 VARCHAR2(20);
C1 VARCHAR2(20);
BEGIN
DBMS_OUTPUT.PUT_LINE('==========================');
OPEN SQL_STMT FOR SELECT EMPNO,ENAME,JOB FROM EMP;
LOOP
FETCH SQL_STMT INTO A1,B1,C1;
EXIT WHEN SQL_STMT%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(A1||' '||B1||'
'||C1);
END LOOP;
----- CLOSE SQL_STMT;
DBMS_OUTPUT.PUT_LINE('==========================');
OPEN SQL_STMT FOR SELECT DEPTNO,DNAME,LOC FROM DEPT;
LOOP
FETCH SQL_STMT INTO A1,B1,C1;
EXIT WHEN SQL_STMT%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(A1||' '||B1||'
'||C1);
END LOOP;
------CLOSE SQL_STMT;
DBMS_OUTPUT.PUT_LINE('==========================');
OPEN SQL_STMT FOR SELECT LOCID,LOC_NAME,COUNTRY FROM LOCMAST;
DBMS_OUTPUT.PUT_LINE('ID LOCNAME
COUNTRY');
DBMS_OUTPUT.PUT_LINE('------------------------------------------------');
LOOP
'||B1||'
'||C1);
REF CURSOR - 3
[ With Procedure ]
IS
BEGIN
UPDATE EMP51 SET SAL=SAL+SAL*.01 WHERE EMPNO=ENO;
END;
EXAMPLE FOR OUT PARAMETER - SPECIFICATION
CREATE OR REPLACE PROCEDURE P50 (ENO IN EMP51.EMPNO%TYPE, ENAME1 OUT EMP51.ENAME%TYPE)
IS
BEGIN
SELECT ENAME INTO ENAME1 from emp51 WHERE EMPNO=ENO;
Dbms_output.Put_Line(ENAME1);
EXCEPTION
WHEN TOO_MANY_ROWS THEN
DBMS_OUTPUT.PUT_LINE('MORE ROWS');
END;
EXAMPLE FOR OUT PARAMETER EXECUTION / BODY
SQL> VARIABLE GNAME VARCHAR2(25)
SQL> EXECUTE P50(7000,:GNAME);
PROCEDURE - IN OUT - SPECIFICATION
CREATE OR REPLACE PROCEDURE
P1002(A1 IN EMP.EMPNO%TYPE,B1 IN OUT EMP.SAL%TYPE) IS
C1 NUMBER;
BEGIN
SELECT SAL INTO B1 FROM EMP WHERE EMPNO=A1;
IF B1<2000 THEN
B1:=B1+200;
ELSE
B1:=B1-100;
END IF;
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('NO EMPS' );
END;
PROCEDURE - IN OUT - BODY - IMPLEMENTATION
DECLARE
B NUMBER;
A NUMBER:=&AA;
BEGIN
P1002(A,B);
DBMS_OUTPUT.PUT_LINE(B);
END;
Procedure - IN - Exception Raise Application Error , IMPLICIT CURSOR
CREATE OR REPLACE PROCEDURE
P1004(A1 IN DEPT.DEPTNO%TYPE,B1 IN DEPT.DNAME%TYPE) IS
BEGIN
UPDATE DEPT SET DNAME=B1 WHERE DEPTNO=A1;
DBMS_OUTPUT.PUT_LINE(SQL%ROWCOUNT);
IF SQL%ROWCOUNT=0 THEN
RAISE_APPLICATION_ERROR(-20204,'INVALID UPDATES, TRY AGAIN');
END IF;
END;
EXEC P1004(10,'SALES1');
Procedure - Implicit Cursor - Explicit Cursor for loop -Update
CREATE OR REPLACE PROCEDURE P1007(DNO1 DEPT.DEPTNO%TYPE) IS
DNO EMP.DEPTNO%TYPE:=DNO1;
CURSOR C1 IS SELECT EMPNO,ENAME,SAL FROM EMP WHERE DEPTNO=DNO;
10
BEGIN
END;
R1 C1%ROWTYPE;
FOR R1 IN C1
LOOP
EXIT WHEN C1%ROWCOUNT>1;
UPDATE EMP SET COMM=SAL*.075 WHERE DEPTNO=DNO AND (SAL>1000 AND SAL<=3000);
END LOOP;
COMMIT;
DBMS_OUTPUT.PUT_LINE(SQL%ROWCOUNT);
Functions
Advantage
Reusability
EXAMPLES
Function Specification
CREATE OR REPLACE FUNCTION F1000(ENO NUMBER) RETURN NUMBER IS
ESAL EMP.SAL%TYPE;
BEGIN
SELECT SAL INTO ESAL FROM EMP WHERE EMPNO=ENO;
RETURN ESAL;
EXCEPTION
WHEN NO_DATA_FOUND THEN
RAISE_APPLICATION_ERROR(-20345,'THIS EMPLOYEE ID NOT EXITST');
END;
Function Body
DECLARE
A NUMBER;
BEGIN
A:=F1000(&EMPNO);
DBMS_OUTPUT.PUT_LINE(A);
END;
Function - Specification
CREATE OR REPLACE FUNCTION F1001(P_VALUE IN NUMBER) RETURN NUMBER IS
BEGIN
RETURN (P_VALUE*0.08);
11
END;
Function Execution at SQL*Plus
SQL>SELECT EMPNO,ENAME,SAL,COMM,F1001(SAL) FROM EMP WHERE DEPTNO=10;
Control indirect access to database objects from non privileged users with security privileges
Ensure that related actions are performed together, or not at all, by funneling activity for related tables
through a single path
Parts of Package
Parts of Package
PACKAGE SPECIFICATION
The package specification contains public declarations. The scope of these declarations is local to your
database schema and global to the package. So, the declared items are accessible from your application and
from anywhere in the package.
12
show err
CREATE
PACKAGE PC1000 IS
PROCEDURE P1100 (A1 IN NUMBER);
END PC1000;
/
show err
------------------------------------------------CREATE OR REPLACE PACKAGE PC1003 IS
FUNCTION
F1103(Z1 IN NUMBER) RETURN NUMBER;
FUNCTION
F1104(Z1 IN NUMBER) RETURN varchar2;
END PC1003;
CREATE OR REPLACE PACKAGE BODY PC1003 IS
FUNCTION F1103(Z1 IN NUMBER) RETURN NUMBER IS
EXP1 EMP.SAL%TYPE;
BEGIN
SELECT (SYSDATE-HIREDATE)/365 INTO EXP1 FROM EMP WHERE EMPNO=Z1;
RETURN EXP1;
END F1103;
FUNCTION F1104(Z1 IN NUMBER) RETURN varchar2 IS
EXP1 EMP.ename%TYPE;
BEGIN
SELECT ename INTO EXP1 FROM EMP WHERE EMPNO=Z1;
RETURN EXP1;
END F1104;
END PC1003;
/
show err
-------------------------------------------------------------------------------DECLARE
A2 NUMBER;
BEGIN
A2:=PC1003.F1103(&EMPNO);
DBMS_OUTPUT.PUT_LINE(A2);
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('EMP NOS NONE');
END;
DECLARE
A2 varchar2(25);
BEGIN
A2:=PC1003.F1104(&EMPNO);
DBMS_OUTPUT.PUT_LINE(A2);
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('EMP NOS NONE');
END;
CREATE OR REPLACE PACKAGE PC1000 IS
PROCEDURE P1101 (A1 IN NUMBER);
FUNCTION
F1101(Z1 IN NUMBER) RETURN varchar2;
END PC1000;
/
show err
CREATE OR REPLACE PACKAGE BODY PC1000 IS
PROCEDURE P1101 (A1 IN NUMBER) IS
ESAL EMP.SAL%TYPE;
BEGIN
SELECT SAL INTO ESAL FROM EMP WHERE EMPNO=A1;
14
DBMS_OUTPUT.PUT_LINE (ESAL);
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE ('EMPNO NO NOT EXISTS');
END P1101;
FUNCTION F1101(Z1 IN NUMBER) RETURN VARCHAR2 IS
EXP1 EMP.ENAME%TYPE;
BEGIN
SELECT ENAME INTO EXP1 FROM EMP WHERE EMPNO=Z1;
RETURN EXP1;
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE ('EMPNO NO NOT EXISTS');
END F1101;
END PC1000;
/
SHOW ERR
DECLARE
A2 VARCHAR2(25);
BEGIN
A2:=PC1000.F1101(&EMPNO);
DBMS_OUTPUT.PUT_LINE(A2);
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('EMP NOS NONE');
END;
=================
CREATE OR REPLACE PACKAGE PC1 IS
PROCEDURE <PROC NAME>;
FUNCTION <FUN NAME> RETURN NUMBER;
END PC1
==================================================================
CREATE OR REPLACE PACKAGE PC1106 IS
PROCEDURE
P1106(dno dept.deptno%type);
END PC1106;
-------------------------CREATE OR REPLACE PACKAGE BODY PC1106 IS
PROCEDURE P1106(dno dept.deptno%type) IS
CURSOR C1 IS SELECT
EMPNO,ENAME,(SYSDATE-HIREDATE)/365
ENO1 NUMBER;
ENAME1 VARCHAR2(25);
EXP1 NUMBER;
SERVICE
BEGIN
OPEN C1;
LOOP
FETCH C1 INTO ENO1,ENAME1,EXP1;
EXIT WHEN C1%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(ENO1||'
'||ENAME1||'
END LOOP;
'||ROUND(EXP1,2) );
CLOSE C1;
END P1106;
END PC1106;
/
15
show err
COMPARING PROCEDURES AND FUNCTIONS
Procedure
Function
No RETURN datatype
SELECT
OBJECT_NAME,
OBJECT_TYPE
FROM
USER_OBJECTS
(PROCEDURE, FUNCTION) ORDER BY OBJECT_NAME
WHERE
OBJECT_TYPE
IN
SELECT TEXT
FROM USER_SOURCE
ORDER BY LINE;
The first procedure accepts trans_date as a character string, while the second procedure accepts it as a number (the Julian
day). Yet, each procedure handles the data appropriately.
CURSOR Cotn
OTHER CURSORS
1 ] DYNAMIC CURSOR
Dynamic Cursor can be used along with DBMS_SQL package .A SQL statement is dynamic, if it is constructed at run time
and then executed.
2 ] REF CURSOR
To execute a multi-row query, Oracle opens an unnamed work area that stores processing information. To access the
information, you can use an explicit cursor, which names the work area. Or, you can use a cursor variable, which points to
the work area.
Mainly, you use cursor variables to pass query result sets between PL/SQL stored subprograms and various clients. Neither
PL/SQL nor any of its clients owns a result set; they simply share a pointer to the query work area in which the result set is
stored. For example, an OCI client, Oracle Forms application, and Oracle Server can all refer to the same work area.
Ref are the best way of uniqely referring to object instances.It is only supported way of getting at OID ( object identifier ).It is
a effecient and light means of passing object information as a information
a] Strong Cursor - Whose return type specified.
b] Week Cursor - Whose return type not specified.
Declaring a cursor variable creates a pointer, not an item. In PL/SQL, a pointer has datatype REF X, where REF is short for
REFERENCE and X stands for a class of objects. Therefore, a cursor variable has datatype REF CURSOR.
DREF
It is the 'deference operator. Like VALUE, it returns the value of an object, Unlike value.
Dref's input is a REF to an column in a table and you want retrieve the target instead of the pointer, you DREF.
CURSOR SUBQUERY
The cursor sub query opens a nested cursor for each evaluation of the cursor expression.
For each row of the parent query, it returns a cursor in the SELECT list corresponding to the cursor
expression.
Fetches have to be performed to retrieve the results of a sub query.
CURSOR SUBQUERY IN REF CURSOR: EXAMPLE
DECLARE
TYPE refcursortype IS REF CURSOR;
n NUMBER;
emprow employees%rowtype;
empcur1 refcursortype;
empcur2 refcursortype;
BEGIN
OPEN empcur1 FOR
SELECT cursor(SELECT * FROM employees) FROM departments;
FETCH empcur1 INTO empcur2;
FETCH empcur2 INTO emprow;
CLOSE empcur1;
END;
CURSOR SUBQUERY IN EXPLICIT CURSOR: EXAMPLE
DECLARE
TYPE REFCURSORTYPE IS REF CURSOR;
EMPCUR1 REFCURSORTYPE;
17
V_DNAME DEPARTMENTS.DEPARTMENT_NAME%TYPE;
OPEN C1;
LOOP
FETCH C1 INTO V_DNAME,EMPCUR1;
FETCH EMPCUR1 INTO EMPROW;
END;
END LOOP;
CLOSE C1;
REF CURSOR
If any normal cursor is declared, we have to give a select statement for that. For example Cursor C_cur is select * from emp;
If you call the cursor C_cur anywhere or anytime, it will execute only this select statement .ie it is meant for the Select * from
emp; If you want to execute multiple select statements, we have to declare multiple cursors. It will be cumbersome. So, if
there is a single cursor which can open multiple select statements, then it will be easy for the programmer.
There are two steps to handle the ref cursor.
1. declaring a ref cursor
2. declaring a variable of the cursor.
The ref cursor can be declared in PL/SQL block, Subprograms and Packages.
Example:
DECLARE
TYPE C_REF IS REF CURSOR;
C_VAR1
C_REF;
BEGIN
C_VAR2
C_REF;
A NUMBER;
B VARCHAR2(20);
C VARCHAR2(20);
END LOOP;
CLOSE C_VAR2;
END;
Thus, with single ref cursor, we can declare any number of cursor variables and each variable can be used for different
select statements.
DATABASE TRIGGERS
A Trigger defines an action the database should take when some database related event occurs. Triggers may be used to
supplement declarative referential integrity, to enforce complex business rules.
A database trigger is a stored subprogram associated with a table. You can have Oracle automatically fire the trigger before
or after an INSERT, UPDATE, or DELETE statement affects the table.
Triggers are executed when a specific data manipulation command are performed on specific tables
ROW LEVEL TRIGGERS
Row Level triggers execute once for each row in a transaction. Row level triggers are create using FOR EACH ROW clause
in the create trigger command.
STATEMENT LEVEL TRIGGERS
Statement Level triggers execute once for each transaction. For example if you insert 100 rows in a single transaction then
statement level trigger will be executed once.
BEFORE and AFTER Triggers
Since triggers occur because of events, they may be set to occur immediately before or after those events.
The following table shows the number of triggers that you can have for a table. The number of triggers you can have a for a
table is 14 triggers.
The following table shows the number of triggers that you can have for a table. The number of triggers you can have a for a
table is 14 triggers.
BEFORE
INSERT
INSERT
UPDATE
UPDATE
DELETE
DELETE
INSTEAD OF
INSTEAD OF ROW
AFTER
INSERT
INSERT
UPDATE
UPDATE
DELETE
DELETE
ADVANTAGES OF TRIGGERS
Feature
Enhancement
Security
The Oracle Server allows table access to users or roles. Triggers allow table access
according to data values.
Auditing
The Oracle Server tracks data operations on tables. Triggers track values for data
operations on tables.
19
Data integrity
The Oracle Server enforces integrity constraints. Triggers implement complex integrity
rules.
Referential integrity
The Oracle Server enforces standard referential integrity rules. Triggers implement
nonstandard functionality.
Table replication
The Oracle Server copies tables asynchronously into snapshots. Triggers copy tables
Synchronously into replicas.
Derived data
The Oracle Server computes derived data values manually. Triggers compute derived data values
automatically.
Event logging
The Oracle Server logs events explicitly. Triggers log events transparently.
Syntax:
CREATE OR REPLACE TRIGGER <TRIGGER NAME> [ BEFORE | AFTER | INSTEAD OF ]
(INSERT OR UPDATE OR DELETE) ON <TABLE NAME>
ROW
FOR EACH
BEGIN
END;
Example 1:
CREATE OR REPLACE TRIGGER MY_TRIG BEFORE INSERT OR UPDATE OR DELETE ON
DETAIL FOR EACH ROW
BEGIN
IF LTRIM(RTRIM(TO_CHAR(SYSDATE,'DAY')))='FRIDAY' THEN
IF INSERTING THEN
RAISE_APPLICATION_ERROR(-20001,'INSERT IS NOT POSSIBLE');
ELSIF UPDATING THEN
RAISE_APPLICATION_ERROR(-20001,'UPDATE IS NOT POSSIBLE');
ELSIF DELETING THEN
RAISE_APPLICATION_ERROR(-20001,'DELETE IS NOT POSSIBLE');
END IF;
END IF;
END;
Example 2:
CREATE OR REPLACE TRIGGER MY_TRIG AFTER INSERT ON
ITEM FOR EACH ROW
DECLARE
MITEMID NUMBER;
MQTY NUMBER;
BEGIN
SELECT ITEMID INTO MITEMID FROM STOCK WHERE ITEMID = :NEW.ITEMID;
UPDATE STOCK SET QTY=QTY+:NEW.QTY WHERE ITEMID=:NEW.ITEMID;
EXCEPTION WHEN NO_DATA_FOUND THEN
INSERT INTO STOCK VALUES (:NEW.ITEMID, :NEW.QTY);
END;
20
Example 3:
CREATE OR REPLACE TRIGGER MY_TRIG AFTER DELETE ON
EMP FOR EACH ROW
BEGIN
INSERT INTO EMP_BACK VALUES (:OLD.EMPNO, :OLD.ENAME, :OLD.SAL, :OLD.DEPTNO);
END;
Example 4:
CREATE OR REPLACE TRIGGER TR02 BEFORE INSERT OR UPDATE OR DELETE ON EMP100
DECLARE
D1 VARCHAR(3);
BEGIN
D1:=TO_CHAR(SYSDATE,'DY');
END;
IF D1 IN('TUE','MON') THEN
RAISE_APPLICATION_ERROR(-20025,'TRY ON ANOTHER DAY');
END IF;
Example 5:
CREATE OR REPLACE TRIGGER TR01 AFTER DELETE ON DEPT200 FOR EACH ROW
BEGIN
INSERT INTO DEPT1 VALUES (:OLD.DEPTNO,:OLD.DNAME,:OLD.LOC);
END;
/
SHOW ERR
Example 6:
CREATE OR REPLACE TRIGGER TR03 AFTER UPDATE ON EMP FOR EACH ROW
BEGIN
UPDATE EMP100 SET SAL=:OLD.SAL*2 WHERE EMPNO=:OLD.EMPNO;
END;
/
SHOW ERR
Example 7:
CREATE OR REPLACE TRIGGER TR05 AFTER UPDATE ON EMP100
DECLARE
U1 VARCHAR2(50);
BEGIN
SELECT USER INTO U1 FROM DUAL;
INSERT INTO USER1 VALUES(U1,SYSDATE,'UPDATE');
END;
/
SHOW ERR
Example 8:
CREATE OR REPLACE TRIGGER TR06 AFTER DELETE ON
DECLARE
U1 VARCHAR2(50);
BEGIN
SELECT USER INTO U1 FROM DUAL;
INSERT INTO USER1 VALUES(U1,SYSDATE,'DELETE');
END;
/
SHOW ERR
EMP100
21
PL/SQL RECORD
A record is a group of related data items stored in fields, each with its own name and datatype. A record containing a field for
each item lets you treat the data as a logical unit. Thus, records make it easier to organize and represent information.
Suppose you have various data about an employee such as name, salary,and hire date. These items are logically related but
dissimilar in type. A record containing a field for each item lets you treat the data as a logical unit. Thus, records make it
easier to organize and represent information.
The attribute %ROWTYPE lets you declare a record that represents a row in a database table. However, you cannot specify
the datatypes of fields in the record or declare fields of your own. The datatype RECORD lifts those restrictions and lets you
define your own records.
There are two steps to declare a record.
1. Declaring a record and 2. Declaring a variable of the record.
DECLARE
TYPE EMP_REC IS RECORD ( A NUMBER(4), B VARCHAR2(30), C NUMBER(10,2));
TYPE DEPT_REC IS RECORD ( A NUMBER(2), B VARCHAR2(30), C VARCHAR2(30));
/* DECLARING RECORD TYPE*/
REC_VAR1
EMP_REC;
REC_VAR2
DEPT_REC;
BEGIN
SELECT EMPNO,ENAME,SAL INTO REC_VAR1 FROM EMP WHERE EMPNO = 7788;
SELECT DEPTNO,DNAME,LOC INTO REC_VAR2 FROM DEPT WHERE DEPTNO = 10;
/* FETCH COLUMN VALUES AND STORE IN THE RECORD VARIABLE*/
DBMS_OUTPUT.PUT_LINE(REC_VAR1.A);
DBMS_OUTPUT.PUT_LINE(REC_VAR1.B);
DBMS_OUTPUT.PUT_LINE(REC_VAR1.C);
DBMS_OUTPUT.PUT_LINE(REC_VAR2.A);
END;
-----
We can't store the record type in the database. We can declare the record type in pl/sql block, subprograms and package.
DECLARE
TYPE R1 IS RECORD(EMPNO NUMBER(5),
ENAME VARCHAR2(10),
HIREDATE DATE);
R2 R1;
BEGIN
WITH PROCEDURE
SET SERVEROUT ON;
CREATE OR REPLACE PROCEDURE PR_PLRECORD (ENO EMP.EMPNO%TYPE) IS
TYPE R1 IS RECORD(EMPNO NUMBER(5),
ENAME VARCHAR2(10),
HIREDATE DATE);
R2 R1;
BEGIN
SELECT EMPNO,ENAME,HIREDATE
INTO R2
FROM EMP
WHERE EMPNO=ENO;
DBMS_OUTPUT.PUT_LINE(R2.EMPNO||'
'||R2.ENAME||'
'||R2.HIREDATE);
EXCEPTION
WHEN NO_DATA_FOUND THEN
RAISE_APPLICATION_ERROR(-20023,'INVALID EMPLOYEE NUMBER');
END;
-------------------------------------------------------------------------------------------WITH CURSOR / PROCEDURE
SET SERVEROUT ON;
CREATE OR REPLACE PROCEDURE PR1 (DNO EMP.DEPTNO%TYPE) IS
TYPE R1 IS RECORD(EMPNO NUMBER(5),
ENAME VARCHAR2(10),
HIREDATE DATE);
R2 R1;
BEGIN
CURSOR C1 IS
SELECT EMPNO,ENAME,HIREDATE
FROM EMP
WHERE DEPTNO=DNO;
OPEN C1;
LOOP
EXIT WHEN C1%NOTFOUND;
FETCH C1 INTO R2;
DBMS_OUTPUT.PUT_LINE(R2.EMPNO||'
'||R2.ENAME||'
'||R2.HIREDATE);
END LOOP;
CLOSE C1;
EXCEPTION
WHEN NO_DATA_FOUND THEN
RAISE_APPLICATION_ERROR(-20023,'INVALID DEPARTMENT NUMBER');
END;
/
SHOW ERR
-------------------------------------------------------------------------------------------WITH CURSOR / PROCEDURE --
JOINS
LOOP
EXIT WHEN C1%NOTFOUND;
FETCH C1 INTO R2;
DBMS_OUTPUT.PUT_LINE(R2.EMPNO||'
END LOOP;
CLOSE C1;
'||R2.ENAME||'
'||R2.HIREDATE||'
'||R2.LOC);
EXCEPTION
WHEN NO_DATA_FOUND THEN
RAISE_APPLICATION_ERROR(-20023,'INVALID DEPARTMENT NUMBER');
END;
/
SHOW ERR
PL/SQL TABLES
PL/SQL tables are temporary array like objects used in a PL/SQL block. The column data type can belong to any scalar data
type.
PL/SQL TABLE EXAMPLE
PL/SQL TABLE - 1
SET SERVEROUT ON;
DECLARE
TYPE R1 IS TABLE OF EMP.ENAME%TYPE INDEX BY BINARY_INTEGER;
R2 R1;
I BINARY_INTEGER:=0;
BEGIN
FOR R3 IN (SELECT ENAME FROM EMP)
LOOP
I:=I+1;
R2(I):=R3.ENAME;
DBMS_OUTPUT.PUT_LINE(R2(I));
END LOOP;
END;
/
SHOW ERR
-------------------------------------------------------------------------------------------PL/SQL TABLE - 2
DECLARE
TYPE R1 IS TABLE OF DEPT%ROWTYPE INDEX BY BINARY_INTEGER;
R2 R1;
BEGIN
FOR I IN 1..10
LOOP
SELECT * INTO R2(I) FROM DEPT WHERE DEPTNO=10;
DBMS_OUTPUT.PUT_LINE(R2(I).DNAME ||'
'||R2(I).LOC||'
R2(I).DEPTNO);
END LOOP;
EXCEPTION
WHEN TOO_MANY_ROWS THEN
RAISE_APPLICATION_ERROR(-20023,'MORE THAN ONE ROWS');
END;
/
=========================
'||
PL/SQL TABLE - 2A
DECLARE
TYPE R1 IS TABLE OF DEPT%ROWTYPE INDEX BY BINARY_INTEGER;
CURSOR C1 IS SELECT * FROM DEPT;
R2 R1;
24
I BINARY_INTEGER:=0;
DNAME VARCHAR2(25);
BEGIN
FOR A IN C1
LOOP
I:=I+1;
DBMS_OUTPUT.PUT_LINE((I)||'
'||A.DEPTNO||'
'||A.DNAME||'
'||
A.LOC);
DNAME:=A.DNAME;
DBMS_OUTPUT.PUT_LINE(DNAME);
END LOOP;
EXCEPTION
WHEN TOO_MANY_ROWS THEN
RAISE_APPLICATION_ERROR(-20023,'MORE THAN ONE ROWS');
END;
PL/SQL TABLE - 3
DECLARE
TYPE R1 IS TABLE OF EMP.ENAME%TYPE INDEX BY BINARY_INTEGER;
R2 R1;
CURSOR C1 IS SELECT ENAME FROM EMP;
I BINARY_INTEGER:=0;
BEGIN
FOR A IN C1
LOOP
I:=I+1;
R2(I):=A.ENAME;
DBMS_OUTPUT.PUT_LINE(R2(I));
END LOOP;
END;
/
PL/SQL TABLE - 4
SET SERVEROUT ON;
CREATE OR REPLACE PROCEDURE PR_PL1 (DNO EMP.DEPTNO%TYPE) IS
TYPE R1 IS TABLE OF EMP.ENAME%TYPE INDEX BY BINARY_INTEGER;
R2 R1;
I BINARY_INTEGER:=0;
BEGIN
FOR R3 IN (SELECT ENAME FROM EMP WHERE DEPTNO=DNO)
LOOP
I:=I+1;
R2(I):=R3.ENAME;
-DBMS_OUTPUT.PUT_LINE(R2(I));
DBMS_OUTPUT.PUT_LINE('MR. '||R2(I));
END LOOP;
EXCEPTION
WHEN NO_DATA_FOUND THEN
RAISE_APPLICATION_ERROR(-20023,'INVALID DEPARTMENT NUMBER');
END;
/
EXEC PR_PL1(20);
EXEC PR_PL1(30);
1.
BEGIN
END;
2.
CALL STATEMENT
This allows you to call a stored procedure, rather than coding the PL/SQL body in the trigger itself.
DYNAMIC SQL:
Static SQL Statement:
Most PL/SQL programs do a specific, predictable job. For example, a stored procedure might accept an employee number
and salary increase, then update the sal column in the emp table. In this case, the full text of the UPDATE statement is
known at compile time. Such statements do not change from execution to execution. So, they are called static SQL
statements.
Dynamic SQL Statement:
However, some programs must build and process a variety of SQL statements at run time. For example, a general-purpose
report writer must build different SELECT statements for the various reports it generates. In this case, the full text of the
statement is unknown until run time. Such statements can, and probably will, change from execution to execution. So, they
are called dynamic SQL statements.
Dynamic SQL statements are stored in character strings built by your program at run time. Such strings must contain the text
of a valid SQL statement or PL/SQL block. They can also contain placeholders for bind arguments. A placeholder is an
undeclared identifier, so its name, to which you must prefix a colon, does not matter.
DYNAMIC SQL
Is a SQL statement stored as character string
Allows general purpose code to be written
Allows DDL statements to be written and executed from PL/SQL
Is written using DBMS_SQL, EXECUTE IMMEDIATE or OPEN-FOR/FETCH/CLOSE
Execute Immediate:
To process most dynamic SQL statements, you use the EXECUTE IMMEDIATE
Statement.
26
27
End;
'||r2(i).deptno);
29
ORACLE 9I
Advanced Explicit Cursor Concepts
1. FOR UPDATE WAIT Clause
Syntax
Cursor eipc1 is select * from emp for update [ of column_reference ] [ NOWAIT ]
Column Reference
NOWAIT
The SELECT... FOR UPDATE statement has been modified to allow the user to specify how
long the command should wait if the rows being selected are locked.
If NOWAIT is specified, then an error is returned immediately if the lock cannot be obtained.
Example of Using FOR UPDATE WAIT Clause
1. SELECT * FROM EMPLOYEES WHERE DEPARTMENT_ID = 10 FOR UPDATE WAIT 20;
2. DECLARE
CURSOR EMP_CURSOR IS
SELECT EMPNO, ENAME, DNAME FROM EMP,DEPT WHERE
EMP.DEPTNO=DEPT.DEPTNO AND EMP.DEPTNONO=80
FOR UPDATE OF SALARY NOWAIT;
[ Retrieve the Employees who work in department 80 and update their Salary ]
2. The WHERE CURRENT OF Clause
Syntax
END IF;
END LOOP;
END;
[ The Example loops through each employee in department 80 , and checks whether the salary is
less than 5000.If salary is less than , the salary is raised by 10%. The where current of clause in the
UPDATE statement refers to the currently fetched records. ]
3. CURSORS WITH SUB QUERIES
Sub queries are often used in the WHERE clause of select statement. It can be used to
FROM clause, creating a temporary data source for the query.
EXCEPTION
In
END LOOP;
CLOSE C1;
END;
31