0% found this document useful (0 votes)
8 views63 pages

PLSQL NOTES

PL/SQL is a procedural language extension for SQL that allows executing multiple statements as a unit, supports variables, error handling, and composite data types. It includes anonymous and named blocks, various data types, and control structures like loops and cursors. The document provides examples of PL/SQL blocks, variable declarations, and cursor usage for database operations.

Uploaded by

sangadaashok104
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
8 views63 pages

PLSQL NOTES

PL/SQL is a procedural language extension for SQL that allows executing multiple statements as a unit, supports variables, error handling, and composite data types. It includes anonymous and named blocks, various data types, and control structures like loops and cursors. The document provides examples of PL/SQL blocks, variable declarations, and cursor usage for database operations.

Uploaded by

sangadaashok104
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 63

1

PL/SQL

WHY PL/SQL
SUPPORTS TO EXECUTE A BLOCK OF ( MULTIPLE ) STATEMENTS AS A UNIT
SUPPORTS VARIABLES & CONSTANTS
SUPPORTS ERROR HANDLING
SUPPORTS TO DEFINE COMPOSITE DATA TYPES
SUPPORTS TO EXECUTE MULTIPLE DDL,DML,TCL COMMANDS AT A TIME
PL/SQL BLOCKS (A SET OF SQL & PL-SQL STATEMENTS)

2 TYPES:-
1) UN NAMED BLOCK (ANONYMOUS BLOCK)
---BLOCK WITH OUT ANY NAME
2) NAMED BLOCK
--BLOCK WITH A PEREMANENT NAME
--PERMANENTLY OBJECT STORED IN THE DATABASE UNTIL YOU DROP
EX: PROCEDURES, FUNCTIONS,TRIGGERS….ETC

BLOCK STRUCTURE (ANONYMOUS OR UN NAMED)

VARIABLE DECLARATION:
1) ALL SQL DATA TYPE ARE SUPPORTED

2) PL/SQL BLOCK SUPPORTED BOOLEAN DATA TYPE ALSO

3) :=  ASSIGNMENT OPERATER IS REQUIRE TO ASSIGN VALUES TO VARIABLES

EXAMPLE:

DECLARE

LN_EMPNO NUMBER(4);

LV_ENAME VARCHAR2(25);

LD_DOJ DATE;

LD_DATE DATE := SYSDATE

FLAG BOOLEAN := TRUE;

BEGIN
2

DBMS_OUTPUT.PUT_LINE(‘HI’);

END;

EXECUTABLE STATEMENTS

1) DML & TCL ARE SUPPORTED

2) DDL ALSO SUPPORTED BUT DYNAMIC SQL IS REQUIRE

3) SELECT STATEMENT ALSO SUPPORT BUT INTO CLAUSE IS REQUIRE

--ONLY ONE RECORD WE CAN SELECT AT A TIME IF WE WANT SELECT MORE


----THEN ONE THEN COMPOSITE DATA TYPE IS REQUIRE

EX: SELECT ENAME INTO LV_ENAME FROM EMP WHERE EMPNO=7369

4) SUPPORTS COMMENTS (-- SINGLE ROW COMMENT, /* MUTLIPLE ROW COMMENTS*/)


5) DBMS_OUTPUT.PUT_LINE (‘HI’); :-- IT IS USED TO PRINT THE MESSAGE OR VARIABLES

WRITE A PL/SQL BLOCK TO DISPLAY SMITH EMPLOYEE DETAILS?


DECLARE
LN_EMPNO NUMBER(4);
LV_ENAME VARCHAR2(20);
LN_SAL NUMBER(7,2);
LD_DOJ DATE;
LN_DEPTNO NUMBER(4);
BEGIN
SELECT EMPNO, ENAME, SAL, HIREDATE, DEPTNO INTO LN_EMPNO, LV_ENAME,
LN_SAL, LD_DOJ, LN_DEPTNO FROM EMP;
DBMS_OUTPUT.PUT_LINE (LN_SAL || LN_DEPTNO);
END;
ADD , MULTIPLY GIVEN TWO NUMBERS AND DISPLAY THE RESULTS?
DECLARE
LN_X NUMBER(3) :=&N;
LN_Y NUMBER(3) := &M;
LN_SUM NUMBER(4);
LN_MULTIPLY NUMBER(4);
BEGIN
LN_SUM := LN_X + LN_Y;
LN_MULTIPLY := LN_X * LN_Y;
DBMS_OUTPUT.PUT_LINE (‘ SUM IS ‘|| LN_SUM);
DBMS_OUTPUT.PUT_LINE (‘ MULTIPLY IS ‘|| LN_MULTIPLY);
END;

ATRIBUTE DECLARATION:
SUPPORTS TO DEFINE THE VARIABLES EYNAMICALLY ACCORDING TO TABLE
STRUCTURE.
3

%TYPE :- COLUMN TYPE DECLARATION USED TO DEFINE VARIABLE ACCORDING TO


SPECIFIE COLUMN IN DATA BASE TABLE
SYNTAX: VARIABLE <TABLE_NAME>.<COLUMN> %TYPE;
EX: EMPNO EMP.EMPNO%TYPE;

%ROWTYPE :- RECORD TYPE DECLARATION USED TO DEFINE VARIABLE REPRESENTING


COMPLETE TABLE STRUCTURE

SYNTX: VARIABLE <TABLE_NAME>%ROWTYPEL


EX: LV_EMP EMP%ROWTYPE;

INTO CLAUSE :
INTO CLAUSE IS USED IN PL/SQL BLOCK TO COLLECT SELECT QUERY RESULTS
(COLUMNS DATA) INTO A LOCAL VARIABLES.

EXAMPLES:
DECLARE

LN_EMPNO_J NUMBER(4);
LN_EMPNO_M EMP.EMPNO%TYPE;
LN_SAL NUMBER;

LV_MILLER_DATA EMP%ROWTYPE;

BEGIN

SELECT * INTO LV_MILLER_DATA FROM EMP WHERE ENAME = 'MILLER';


DBMS_OUTPUT.PUT_LINE(LV_MILLER_DATA.EMPNO || ' ' || LV_MILLER_DATA.ENAME || ' '
|| LV_MILLER_DATA.SAL || ' ' || LV_MILLER_DATA.JOB);

SELECT EMPNO, SAL INTO LN_EMPNO_J, LN_SAL FROM EMP WHERE ENAME = 'JONES';
--DBMS_OUTPUT.PUT_LINE( LN_EMPNO||' '||LN_SAL);
SELECT EMPNO, SAL
INTO LN_EMPNO_M, LN_SAL
FROM EMP
WHERE ENAME = 'MILLER';
DBMS_OUTPUT.PUT_LINE(LN_EMPNO_J || ' ' || LN_EMPNO_M);
END;

LOOPS IN PL/SQL (ITERATION CONTROL STATEMENTS)


--WHILE LOOP
--FOR LOOP
--INFINITE LOOP
PRINT 1 TO 100 NUMBERS BY USING LOOPS?
--FOR LOOP
DECLARE
X NUMBER(3);
4

BEGIN
FOR I IN1..100 LOOP
X := I;
DBMS_OUTPUT.PUT_LINE(X);
END LOOP;
END;
WHILE LOOP
DECLARE
X NUMBER(3) :=0;
BEGIN
WHILE (X < 101) LOOP
X := X + 1;
DOPL(X);
END LOOP;
END;

--LOOPS EXAMPLES
declare
ln_x number := &n;
ln_y number := 1;
ln_z number := ln_x;
begin
while (ln_y < 10) loop
ln_y := ln_y + 1;
dbms_output.put_line( 'this is y value :'||ln_y);

ln_x := ln_z;

while (ln_x < 101) loop


ln_x := ln_x + 1;

if mod(ln_x, 2) = 0 then
dbms_output.put_line(ln_x);
end if;

end loop;
end loop;
dbms_output.put_line('hi good morning');
end;

CURSORS:-
1) CURSORS ARE 2 TYPES

1) IMPLICIT CURSOR 2) EXPLICIT CURSOR 3)REFCURSOR

2) CURSORS ARE VALID IN PL/QL BLOCK


5

3) THEY ARE NOT RE-USABLE

4) THEY ARE NOT STORED IN DATABASE

5) CURSOR MEANS TEMPORARY MEMORY

IMPLICIT CURSOR:
AUTOMATICALLY CREATED BY ORACLE WHENEVER USER PERFORMS DML OPERATIONS IN PL/SQL BLOCK
 IT WILL GIVE THE STATUS OF DML OPERATION
 IT WILL GIVE THE SINGLE ROW SELECT STATEMENT STATUS
 IT HAS A STANDARD NAME ‘SQL’
 IMPLICIT CURSOR ATRIBUTES ARE
%FOUND , %NOTFOUND , %ROWCOUNT
%FOUND:-IT WILL RETURN BOOLEAN VALUE (TURE OR FALSE ONLY) , IF DML OPERATION IS SUCCESS
THEN RETURNS TRUE ELSE RETURN FALSE , IF SELECT STATEMENT IS SUCCESS FULLY EXECUTED THEN
RETURN TRUE (MEANS: IF SELECT STATEMENT FIND ONE RECORD THEN RETURN TRUE )
%NOTFOUND:-IT WILL RETURN BOOLEAN VALUE (TURE OR FALSE ONLY) , IF DML OPERATION DIN’T
UPDATE ANY RECORD OR NOT DELETED ANY RECORD OR NOT INSERTED ANY RECORD THEN RETURNS
TRUE ELSE FALSE , IF SELECT STATEMENT IS SUCCESS FULLY NOT EXECUTED THEN RETURN TRUE (MEANS:
IF SELECT STATEMENT FIND ONE RECORD THEN RETURN FALSE )
%ROWCOUNT:- RETURN NUMBER
GIVES NUMBER , HOW MANY ROWS DELETED OR UPDATED OR INSERTED
IF SELECT STATEMENT FETCHED ONE RECORD THEN IT WILL GIVE 1

--IMPLICIT CURSOR EXAMPLES


--EXAMPLE 1

DECLARE
LN_COUNT NUMBER(10);
BEGIN
UPDATE EMP E
SET E.COMM =
(SAL * 10 / 100) + NVL(COMM, 0)
WHERE E.DEPTNO = 10;
DBMS_OUTPUT.PUT_LINE(SQL%ROWCOUNT);

DELETE FROM EMP WHERE DEPTNO = 30;


LN_COUNT := (SQL%ROWCOUNT);
DBMS_OUTPUT.PUT_LINE(SQL%ROWCOUNT);
END;

--2ND EXAMPLE

DECLARE
LN_COUNT NUMBER(10);
LN_EMPNO NUMBER(10);
LN_SAL VARCHAR2(30);
BEGIN
6

--INSERT RECORD IN EMP TABLE


INSERT INTO EMP
(EMPNO, ENAME, SAL, DEPTNO)
VALUES
(1001, 'HARI', 1200, 10);
IF SQL%FOUND THEN
--CREATE TABLE AUDIT_EMP AS select * from EMP WHERE 1=2;
INSERT INTO AUDIT_EMP
SELECT * FROM EMP WHERE EMPNO = 1001;
ELSIF SQL%NOTFOUND THEN
DBMS_OUTPUT.PUT_LINE('RECORD IS NOT INSERTED IN EMP TABLE');
END IF;
--DISPLAY SMITH SALARY AND EMPNO FROM EMP TABLE?
SELECT EMPNO, SAL INTO LN_EMPNO, LN_SAL FROM EMP WHERE ENAME = 'SMITH';
DBMS_OUTPUT.PUT_LINE(LN_EMPNO || ' ' || LN_SAL || ' ' ||
SQL%ROWCOUNT);
IF SQL%FOUND THEN
DBMS_OUTPUT.PUT_LINE('SELECT STAATEMENT EXECUTED SUCCESS FULLY AND FIND
SALARY , EMPNO OF SMITH EMPLOYEE');
END IF;
EXCEPTION
WHEN OTHERS THEN
IF SQL%NOTFOUND THEN
DBMS_OUTPUT.PUT_LINE('SELECT STATEMENT IS FAILED');
END IF;
END;

--EXAMPLE 3
DECLARE
LN_COUNT NUMBER;
BEGIN
DELETE FROM EMP WHERE DEPTNO IN (10, 40);
LN_COUNT := SQL%ROWCOUNT;
IF SQL%FOUND THEN
DBMS_OUTPUT.PUT_LINE(LN_COUNT || ' ROWS DELETED SUCCESS FULLY');
ELSIF SQL%NOTFOUND THEN
DBMS_OUTPUT.PUT_LINE('NO RECODS DELETED FROM EMP TABLE');
END IF;
END;

EXPLICIT CURSORS

CURSOR :-> CURSOR IS A PRIVATE AREA CREATED BY PL/SQL BLOCK TO


EXECUTE CURSOR SELECT STATEMENTS IN PL/SQL BLOCK.
7

EXPLICIT CURSOR TYPES:-


1)CURSOR WITH DECLARATION (DEFAULT EXPLICIT CURSOR)
2)CURSOR DECLARATION WITH PARAMETERS
3)CURSOR FOR LOOP
4)CURSOR FOR LOOP WITH SELECT STATEMENTS

EXPLICIT CURSOR ATTRIBUTES


%FOUND:-IT IS A BOOLEAN VALUE RETURN TRUE OR FALSE
IF THE LAST FETCH RETURNED A ROW THEN CURSOR_NAME%FOUND IS TRUE ELSE FALSE
IF THE LAST FETCH NOT RETURNED A ROW THEN CURSOR_NAME%FOUND IS FALSE ELSE TRUE
%NOTFOUND:- IT IS A BOOLEAN VALUE RETURN TRUE OR FALSE
IF THE LAST FETCH NOT RETURNED A ROW THEN CURSOR_NAME%NOTFOUND IS TRUE ELSE FALSE
IF THE LAST FETCH RETURNED A ROW THEN CURSOR_NAME%NOTFOUND IS FALSE ELSE TRUE
EXIT WHEN (CURSOR_NAME%NOTFOUND);
%ROWCOUNT:- RETURN NUMBER
IF THE LAST FETCH RETURNED A ROW THEN CURSOR_NAME%ROWCOUNT GIVES 1 ELSE 0
%ISOPEN:- IF A CURSOR IS OPEN, CURSOR_NAME%ISOPEN RETURNS TRUE; OTHERWISE, IT
RETURNS FALSE.

EXAMPLES (CURSOR WITH DECLARATION):-


EXAMPLE 1
-------------------
DECLARE
CURSOR CUR_EMP_DATA IS
SELECT * FROM EMP;
VCUR_EMP EMP%ROWTYPE;
BEGIN
OPEN CUR_EMP_DATA;
LOOP
FETCH CUR_EMP_DATA
INTO VCUR_EMP;
--%FOUND %ROWCOUNT
IF CUR_EMP_DATA%FOUND THEN
DOPL(‘CURSOR FETCHED ON RECORD’);
DOPL(CUR_EMP_DATA%ROWCOUNT);
END IF;
--%NOTFOUND
EXIT WHEN (CUR_EMP_DATA%NOTFOUND);
DBMS_OUTPUT.PUT_LINE(VCUR_EMP.EMPNO || ' ENAME : ' ||
VCUR_EMP.ENAME || ' SALARY :' || VCUR_EMP.SAL);
END LOOP;

---%ISOPEN
IF CUR_EMP_DAT%ISOPEN THEN

CLOSE CUR_EMP_DATA;
END IF;
END;
8

EXPLICIT CURSOR EXAMPLE 2:


---------------------------------------------
DECLARE
CURSOR CUR_EMP IS
SELECT * FROM EMP;
VC_EMP EMP%ROWTYPE;
BEGIN
OPEN CUR_EMP;
LOOP

FETCH CUR_EMP
INTO VC_EMP;
EXIT WHEN(CUR_EMP%NOTFOUND);

DBMS_OUTPUT.PUT_LINE(VC_EMP.EMPNO || ' ENAME ' ||


VC_EMP.ENAME || ' SALARY ' || VC_EMP.SAL ||
' JOB ' || VC_EMP.JOB);

END LOOP;
CLOSE CUR_EMP;
END;

EXPLICIT CURSOR EXAMPLE 3:


-------------------------------------------
DECLARE
CURSOR CUR_EMPSAL IS SELECT EMPNO, ENAME, SAL FROM EMP;

LN_EMPNO EMP.EMPNO%TYPE;
LN_SAL EMP.SAL%TYPE;
LV_ENAME VARCHAR2(30);
BEGIN
OPEN CUR_EMPSAL;
LOOP
FETCH CUR_EMPSAL INTO LN_EMPNO, LV_ENAME, LN_SAL;
EXIT WHEN (CUR_EMPSAL%NOTFOUND);

DBMS_OUTPUT.PUT_LINE( 'EMPNO :'||LN_EMPNO);


DBMS_OUTPUT.PUT_LINE( 'ENAME :'||LV_ENAME);
DBMS_OUTPUT.PUT_LINE( 'SAL :'||LN_SAL);
DBMS_OUTPUT.PUT_LINE( '');
END LOOP;
CLOSE CUR_EMPSAL;
DBMS_OUTPUT.PUT_LINE( ' HI');
END;

2)CURSOR DECLARATION WITH PARAMETERS


EXAMPLES 1:

DECLARE
9

CURSOR CUR_EMP(P_DEPTNO NUMBER) IS


SELECT ENAME, DEPTNO FROM EMP WHERE DEPTNO = P_DEPTNO;

LV_ENAME EMP.ENAME%TYPE;
LN_DEPTNO EMP.DEPTNO%TYPE;

X NUMBER := &N;
BEGIN
OPEN CUR_EMP(X);
LOOP
FETCH CUR_EMP
INTO LV_ENAME, LN_DEPTNO;
EXIT WHEN(CUR_EMP%NOTFOUND);
DBMS_OUTPUT.PUT_LINE(LV_ENAME || ' ' || LN_DEPTNO);
END LOOP;
CLOSE CUR_EMP;
END;

EXAMPLES 2:

DECLARE
CURSOR CUR_EMP(P_DEPTNO NUMBER, P_SAL NUMBER) IS
SELECT ENAME, DEPTNO FROM EMP WHERE DEPTNO = P_DEPTNO
AND SAL = P_SAL;
LV_ENAME EMP.ENAME%TYPE;
LN_DEPTNO EMP.DEPTNO%TYPE;

BEGIN
OPEN CUR_EMP(10,1300);
LOOP
FETCH CUR_EMP
INTO LV_ENAME, LN_DEPTNO;
EXIT WHEN(CUR_EMP%NOTFOUND);
DBMS_OUTPUT.PUT_LINE(LV_ENAME || ' ' || LN_DEPTNO);
END LOOP;
CLOSE CUR_EMP;
END;
CURSOR FOR LOOP
IF WE ARE USING CURSOR FOR LOOP THEN AUTOMATICALL OPEN CURSOR AND FETCH
THE RECORDS , NO NEED WRITE SEPARATILY FETCH,OPEN AND CLOSE_CURSOR STATE
MENTS
DECLARE
CURSOR CUR_EMP IS
SELECT * FROM EMP;
LN_BONUS NUMBER(5);
BEGIN
FOR VC IN CUR_EMP LOOP
IF VC.DEPTNO IN (10, 20) THEN
10

LN_BONUS := VC.SAL * 10 / 100;


ELSIF VC.DEPTNO = 30 THEN
LN_BONUS := VC.SAL * 20 / 100;
END IF;
DBMS_OUTPUT.PUT_LINE(VC.EMPNO || ' ENAME : ' || VC.ENAME ||
' BONUS ' || LN_BONUS);
END LOOP;
END;

CURSOR FOR LOOP WITH SELECT STATEMENT


IF WE ARE USING CURSOR FOR LOOP WITH SELECT STATEMENT THEN AUTOMATICALL
OPEN CURSOR AND FETCH THE RECORDS , MEANS NO NEED DECLARE THE CURSOR ,
OPEN THE CURSOR ,FETCH THE RECORDS AND CLOSE_CURSOR.
--HOW TO CALCULATE BONUS AND UPDATE BONUS VALUES IN EMP TABLE?
DECLARE
LN_BONUS NUMBER(10, 2);
BEGIN
--ALTER TABLE EMP ADD BONUS NUMBER(10,2);
FOR CUR_EMP IN (SELECT * FROM EMP) LOOP

IF CUR_EMP.DEPTNO IN (10, 20) THEN


LN_BONUS := CUR_EMP.SAL * 10 / 100;
ELSIF CUR_EMP.DEPTNO = 30 THEN
LN_BONUS := CUR_EMP.SAL * 20 / 100;
ELSE
LN_BONUS := 0;
END IF;

UPDATE EMP SET BONUS = LN_BONUS WHERE EMPNO = CUR_EMP.EMPNO;

END LOOP;
COMMIT;
END;

REF CURSOR (REFRENCE CURSOR):-


A CURSOR IS ALWAYS ASSOCIATE WITH SAME RESULT SET BUT REF
CURSOR CAN BE ASSIGNED TO DIFFERENT RESULT SETS.
REF CURSORS ARE TWO TYPES
1) WEAK REF CURSOR
2) STRONG REF CURSOR
WEAK REFCURSOR:- AT THE TIME OF REF CURSOR DECLARATION IF YOU DIN’T MENTION THE TABLE
NAME THEN THAT REF CURSOR IS CALLED AS A WEAK REF CURSOR

STRONG REFCURSOR:- AT THE TIME OF REF CURSOR DECLARATION IF YOU MENTION THE TABLE NAME
THEN THAT REF CURSOR IS CALLED AS A STRONG REF CURSOR

--STRONG REF CURSOR EXAMPLE


declare
11

TYPE TYP_REF IS REF CURSOR RETURN EMP%ROWTYPE;


TYP_R TYP_REF;

VC_EMP EMP%ROWTYPE;
VC_DEPT DEPT%ROWTYPE;
BEGIN
dbms_output.put_line('');

OPEN TYP_R FOR


select * from EMP;
LOOP
FETCH TYP_R
INTO VC_EMP;
EXIT WHEN(TYP_R%NOTFOUND);

dbms_output.put_line(VC_EMP.EMPNO || ' JOB :---'||VC_EMP.JOB);


END LOOP;
CLOSE TYP_R;
--WE CAN'T WRITE BELOW STATEMENT BECAUSE STRONG REF CURSOR ALWAYS
ASSOCIATED WITH EMP RESULT SET ONLY

/* OPEN TYP_R FOR


select * from DEPT;*/
END;

WEAK REF CURSOR EXAMPLE


DECLARE
TYPE TYP_REF IS REF CURSOR;
TYP_R TYP_REF;
VC_EMP EMP%ROWTYPE;
VC_DEPT DEPT%ROWTYPE;
BEGIN
OPEN TYP_R FOR
SELECT * FROM EMP;
LOOP
FETCH TYP_R
INTO VC_EMP;
EXIT WHEN(TYP_R%NOTFOUND);
DBMS_OUTPUT.PUT_LINE(VC_EMP.EMPNO);
END LOOP;
----
OPEN TYP_R FOR
SELECT * FROM DEPT;
LOOP
FETCH TYP_R
INTO VC_DEPT;
EXIT WHEN(TYP_R%NOTFOUND);
DBMS_OUTPUT.PUT_LINE(VC_DEPT.DNAME);
END LOOP;
END;
12

SYS_REFCURSOR :-
SYSTEM DEFINED REF CURSOR (ORACLE PREDEFINED REFERENCE CURSOR),
1) WE CAN USE SYS_REFCURSOR TYPE AS OUT OR IN OR INOUT PARAMETER.
2) EVEN WE CAN DECLARE THE VARIABLES ALSO AS SYS_REFCURSOR ( WHEN WE WANT TO STORE
ENTIRE TABLE INFROMATION INTO VARIABLE THAT TIME THAT VARIABLE YOU CAN DECLARE AS A
SYS_REFCURSOR)
3) WE CAN USE SYS_REFCURSOR AS A FUNCTION RETURN STATEMENT .
4) INSTEAD OF CREATING GLOBAL REF_CURSOR OR INSTEAD OF DECLARE REF CURSOR IN YOUR
PROGRAM YOU CAN USE SYS_REFCURSOR DIRECTLY.
EXAMPLES
DECLARE
LR_REF SYS_REFCURSOR;
REF_EMP EMP%ROWTYPE;
BEGIN
OPEN LR_REF FOR
SELECT * FROM EMP;
LOOP
FETCH LR_REF
INTO REF_EMP;
EXIT WHEN(LR_REF%NOTFOUND);
DBMS_OUTPUT.PUT_LINE(REF_EMP.ENAME || ' ' || REF_EMP.SAL);
END LOOP;
END;

FUNCTIONS
1) IT IS A NAMED BLOCK
2) FUNCTION MUST HAVE A RETURN TYPE
3) FUNCTIONS ARE MAINLY USED TO DO SIMPLE CALCULTIONS OR WANT TO
DISPLAY SOMETHING IN PL/SQL ,THEN FUNCTIONS ARE PREFERABLE
4) FUNCTIONS MUST RETURN A VALUE (ATLEAST RETURN NULL VALUE)
5) WE CAN CALL FUNCTIONS INSIDE SELECT STATEMENT
6) IF YOU USE DML OPERATIONS INSIDE THE FUNCTION THEN THOSE FUNCTIONS
YOU CAN’T CALL INSIDE SELECT STATEMENT
7) IF YOU ARE USING DML OPERATION INSIDE SELECT STATEMENT THEN PRAGMA
AUTONAMOUS_TRANSACTION IS REQUIRE TO CALL THAT FUNCTION INSIDE
SELECT STATEMENT
8) IF YOU ARE USING OUT PARAMETER IN FUNCTION THEN THAT FUNCTION ALSO
YOU CAN’T CALL INSIDE SELECT STATEMENT (SO OUT PARAMETERS IS NOT
RECOMMENDABLE IN FUNCTIONS BUT IF YOU WANT YOU CAN USE)

EXAMPLE 1:-
DO SUM OR MULTIPLICATION OR SUBSTRACTION OF TWO NUMBERS BASED ON
OPERATION TYPE?

CREATE OR REPLACE FUNCTION SF_SUM_OF_NUMBERS(P_NUM1 IN NUMBER


, P_NUM2 IN NUMBER,P_TYPE IN VARCHAR2 )
RETURN NUMBER AS
13

LN_SUM NUMBER;
BEGIN
IF P_TYPE = 'SUM' THEN
LN_SUM := P_NUM1 + P_NUM2;
ELSIF P_TYPE = 'MUL' THEN
LN_SUM := P_NUM1 * P_NUM2;
ELSE
LN_SUM := P_NUM1 - P_NUM2;
END IF;

RETURN LN_SUM;
END;

EXAMPLE 2:-
FIND EMPLOYEE NAME BASED ON GIVEN EMPNO?
CREATE OR REPLACE FUNCTION SF_ENAME(P_EMPNO NUMBER) RETURN VARCHAR2 AS
LV_ENAME EMP.ENAME%TYPE;
BEGIN
SELECT E.ENAME INTO LV_ENAME FROM EMP E WHERE E.EMPNO = P_EMPNO;
RETURN LV_ENAME;
END;

SYS_REFCURSOR FUNCTION RETURN TYPE:

CREATE OR REPLACE FUNCTION SF_EMP_DATA(P_DEPTNO IN NUMBER)


RETURN SYS_REFCURSOR AS
REF_EMP SYS_REFCURSOR;
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
INSERT INTO EMP (EMPNO) VALUES
(8989);
COMMIT;
--DBMS_OUTPUT.PUT_LINE( 'HI RAJA');
OPEN REF_EMP FOR
SELECT E.EMPNO, E.ENAME, E.SAL, D.DNAME, D.LOC
FROM EMP E, DEPT D
WHERE E.DEPTNO = P_DEPTNO
AND E.DEPTNO = D.DEPTNO;
RETURN REF_EMP;
END;

--OUT PARAMETER IN FUNCTION EXAMPLE


CREATE OR REPLACE FUNCTION SF_DISPLAY_EMP2(P_DEPTNO IN NUMBER,
P_OUT_COUNT OUT NUMBER)
RETURN EMP%ROWTYPE AS
LN_COUNT NUMBER;
REF_EMP SYS_REFCURSOR;
REF_EMP2 EMP%ROWTYPE;
BEGIN
select COUNT(*) INTO LN_COUNT from EMP WHERE DEPTNO = P_DEPTNO;
OPEN REF_EMP FOR
14

select E.*,LN_COUNT from EMP E WHERE DEPTNO = P_DEPTNO;


LOOP
FETCH REF_EMP INTO REF_EMP2;
EXIT WHEN (REF_EMP%NOTFOUND);
END LOOP;

P_OUT_COUNT := LN_COUNT;
RETURN REF_EMP2;
END SF_DISPLAY_EMP2;
/
--OUT PARAMETER IN FUNCTION EXAMPLE
CREATE OR REPLACE FUNCTION SF_DISPLAY_EMP(P_DEPTNO IN NUMBER,
P_OUT_COUNT OUT NUMBER)
RETURN SYS_REFCURSOR AS
LN_COUNT NUMBER;
REF_EMP SYS_REFCURSOR;
GG
BEGIN
OPEN REF_EMP FOR
select * from EMP WHERE DEPTNO = P_DEPTNO;
select COUNT(*) INTO LN_COUNT from EMP WHERE DEPTNO = P_DEPTNO;

P_OUT_COUNT := LN_COUNT;
RETURN REF_EMP;
END SF_DISPLAY_EMP;
/
CURSOR FOR UPDATE STATEMENT:-
IF YOU WRITE FOR UPDATE IN CURSOR SELECT STMT EXCLUSIVELY ROW LEVEL LOCK
APPLIED ON ALL THE ROWS WHICH ARE IDENTIFIED BY CURSOR SELECT STAEMENT.
HOLDING THOSE RECORDS FOR OUR CHANGES ONLY UNTIL YOU GIVE COMMIT OR
ROLLBACK .NO ONE ELSE WILL BE DOANY CHANGES
**DON’T WRITE TCL COMMAMDS INSIDE CURSOR FOR LOOP (IF THAT IS CURSOR FOR
UPDATE STATEMENT)
--CURSOR FOR UPDATE EXAMPLES
CREATE OR REPLACE PROCEDURE SP_EMP_INFO AS

CURSOR C1 IS
SELECT * FROM EMP FOR UPDATE;
VEC EMP%ROWTYPE;
BEGIN
OPEN C1;
LOOP
FETCH C1
INTO VEC;
EXIT WHEN(C1%NOTFOUND);
UPDATE EMP E SET SAL = SAL + 100 WHERE E.EMPNO = VEC.EMPNO;
--COMMIT;
/* DON'T WRITE TCL COMMANDS HERE BECUAUSE LOCK WILL BE
RELEASED AND EVEN SYSTEM ALSO WON'T ALLOW TO GIVE TCL COMMAND
*/END LOOP;
CLOSE C1;
15

COMMIT; --END OF THE LOOP YOU CAN WRITE COMMIT STATEMENT


END;

PROCEDURE EXAMPLES

CREATE OR REPLACE PROCEDURE SP_EMP_INFO(P_DEPTNO IN NUMBER,


P_OUT_EMP OUT SYS_REFCURSOR,
P_OUT_DEPTNO OUT NUMBER) AS

CURSOR C1 IS
SELECT * FROM EMP WHERE DEPTNO = P_DEPTNO;
VEC EMP%ROWTYPE;
REF_EMP SYS_REFCURSOR;
LN_COUNT NUMBER;
BEGIN
OPEN C1;
LOOP
FETCH C1
INTO VEC;
EXIT WHEN(C1%NOTFOUND);
UPDATE EMP E
SET SAL = SAL + (SAL * 13 / 100)
WHERE E.EMPNO = VEC.EMPNO;
END LOOP;
CLOSE C1;
OPEN REF_EMP FOR
SELECT * FROM EMP WHERE DEPTNO = P_DEPTNO;
P_OUT_EMP := REF_EMP;
COMMIT;
SELECT COUNT(*) INTO LN_COUNT FROM EMP WHERE DEPTNO = P_DEPTNO;
P_OUT_DEPTNO := LN_COUNT;
END;
RETURN STATEMENT IN PROCEDURE
CREATE OR REPLACE PROCEDURE SP_EMP_INFO(P_DEPTNO IN NUMBER,
P_OUT_EMP OUT SYS_REFCURSOR,
P_OUT_DEPTNO OUT NUMBER) AS

CURSOR C1 IS
SELECT * FROM EMP WHERE DEPTNO = P_DEPTNO;
VEC EMP%ROWTYPE;
REF_EMP SYS_REFCURSOR;
LN_COUNT NUMBER;
BEGIN
IF P_DEPTNO > 10 THEN

RETURN;
END IF;
OPEN C1;
LOOP
FETCH C1
INTO VEC;
16

EXIT WHEN(C1%NOTFOUND);
UPDATE EMP E
SET SAL = SAL + (SAL * 13 / 100)
WHERE E.EMPNO = VEC.EMPNO;
END LOOP;
CLOSE C1;
OPEN REF_EMP FOR
SELECT * FROM EMP WHERE DEPTNO = P_DEPTNO;
P_OUT_EMP := REF_EMP;
COMMIT;
SELECT COUNT(*) INTO LN_COUNT FROM EMP WHERE DEPTNO = P_DEPTNO;
P_OUT_DEPTNO := LN_COUNT;
END;
DIFFERENCE BETWEEN PROCEDURE AND FUNCTION.

FUNCTION PROCEDURE
FUNCTION WE CAN CALL INSIDE SELECT PROCEDURE WE CAN’T CALL INSIDE
STATEMENT SELECT STATEMENT
FUNCTION MUST RETURN A VALUE PROCEDURE MAY OR MAY NOT RETURN A
VALUE
WE CAN USE RETURN STMT IN FUNCTION WE CAN USE RETURN; IN PROCEDURE BUT
THIS RETURN; WILL TERMINATE THE
PROGRAM(THIS RETURN STATEMENT NOT
WORK LIKE FUNCTION RETURN STMT)
WE CAN USE DML OPERATION IN WE CAN USE DML OPERATION IN
FUNCTION BUT THAT FUNCTION WE CAN’T PROCEDURE
CALL INSIDE SELECT STATEMENT
IF I WANT TO CALL DML _FUNCTION IN WE CAN’T CAL PROCEDURE IN SELECT
SELECT STATEMENT THEN PRAGMA STMT
AUTONOMOUS_TRANSACTION IS REQUIRE
OUT PARAMETER IS NOT REQUIRE IN IF I WANT TO RETRIVE SOMETHING IN
FUNCTION BECAUSE FUNCTION MUST PROCEDURE THEN OUT PARAMETER IS
RETURN A VALUE REQUIRE
IF YOU USE OUT PARAMETER IN FUNCTION WE CAN’T CAL PROCEDURE IN SELECT
THEN THAT FUNCTION WE CAN’T CALL STMT
INSIDE SELECT STMT
17

EXCEPTIONS:-
AN EXCEPTION IS A RUNTIME ERROR (An exception is an event, which occurs during the
execution of a program)
ERRORS ARE TWO TYPES 1) COMPILATION ERROR 2) RUNTIME ERROR(EXCEPTIONS)
EXCEPTIONS ARE 3 TYPES
1) PREDEFINED EXCEPTION
2) USER DEFINED EXCEPTION
3) NON PREDEFINED EXCEPTION(USER NAMED EXCEPTION)

PREDEFINED EXCEPTIONS:

NO_DATA_FOUND :- WHEN SELECT STMT IS UNABLE TO RETRIEVE DATA INTO PL/SQL


VARIABLES
TOO_MANY_ROWS:- WHEN SELECT STMT RETRIEVES MORE THEN ONE ROW INTO
PL/SQL VARIABLES
VALUE_ERROR:- WHEN DATATYPES ARE NOT MATCHED OR WHEN WE ARE TRYING TO
STORE LARGER VALUE INTO SMALLER VARIABLE.
DUP_VAL_ON_INDEX :- WHEN WE ARE TRYING TO INSERT DUPLICATE VALUES IN
PRIMARY/UNIQUE KEY COLUMNS OR UNIQUE INDEX COLUMNS
INVALID_CURSOR:- WHEN USER TRIES TO FETCH ROWS WITHOUT OPENING THE
CURSOR OR WHEN WE ARE TRYING TO OPEN THE CURSOR WITH A WRONG NAME
CURSOR_ALREADY_OPEN :- WHEN WE ARE TRYING OPEN THE CURSOR WITHOUT
CLOSING IT
STORAGE_ERROR:- WHEN SERVER IS OUT OF MEMORY
TIME_OUT_ON_RESOURCES:- ACTIVATED WHEN USER PERFORMS INFINITE LOOP
PROCESS
ZERO_DEVIDE:- WHEN USER TRY TO DEVIDE ZERO WITH ANY NUMBER
LOGIN_DENIED:- ACTIVATED WHEN USER NAME AND PASSWORD ARE NOT VALID
PROGRAM_ERROR:- IT OCCURS WHEN INTERNAL PL/SQL ERROR HAPPENS
WHEN OTHERS :- IT WILL HANDLE ANY TYPE OF ORACLE RUNTIME ERROR,THIS
EXCEPTION YOU HAVE TO WRITE END OF ALL THE EXCEPTIONS
SQLCODE :- IT WILL GIVE ERROR NUMBER
18

SQLERRM :- IT WILL GIVE ERROR DESCRIPTION(size 512)

EXAMPLES:-
CREATE OR REPLACE PROCEDURE SP_GET_SAL_2(P_NUM NUMBER, P_OUT_SAL OUT
NUMBER) AS
LN_SAL NUMBER;
LV_CODE VARCHAR2(10);
LV_ERRMSG VARCHAR2(250);

LN_COUNT NUMBER(2);
CURSOR CUR_1 IS SELECT * FROM EMP;
BEGIN
OPEN CUR_1;
-- OPEN CUR_1;
LN_COUNT := 'RAJA';
LN_COUNT := 10/0;
--- SELECT 0/20 INTO LN_COUNT FROM DUAL;
SELECT SAL INTO LN_SAL FROM EMP WHERE DEPTNO = P_NUM;
P_OUT_SAL := LN_SAL;
DBMS_OUTPUT.PUT_LINE('HI');
COMMIT;
EXCEPTION
WHEN OTHERS THEN
LV_CODE := SQLCODE;
LV_ERRMSG := SQLERRM;
INSERT INTO ERROR_LOG
VALUES
('SP_GET_SAL', LV_CODE,LV_ERRMSG,
SYSDATE);
COMMIT;

END SP_GET_SAL_2;

EXAMPLE 2

CREATE OR REPLACE PROCEDURE P_GET_SAL(P_NUM NUMBER, P_OUT_SAL OUT


NUMBER) AS
LN_SAL NUMBER;
LV_CODE VARCHAR2(10);
LV_ERRMSG VARCHAR2(250);

LN_COUNT NUMBER(2);
CURSOR CUR_1 IS SELECT * FROM EMP;
BEGIN
LOOP
LN_COUNT := 1;
END LOOP;
OPEN CUR_1;
OPEN CUR_1;
LN_COUNT := 'RAJA';
LN_COUNT := 10/0;
19

--- SELECT 0/20 INTO LN_COUNT FROM DUAL;


SELECT SAL INTO LN_SAL FROM EMP WHERE DEPTNO = P_NUM;
P_OUT_SAL := LN_SAL;
DBMS_OUTPUT.PUT_LINE('HI');
COMMIT;
EXCEPTION
WHEN NO_DATA_FOUND THEN
LV_CODE := SQLCODE;
LV_ERRMSG := SQLERRM;
INSERT INTO ERROR_LOG
VALUES
('SP_GET_SAL', LV_CODE, LV_ERRMSG, SYSDATE);
COMMIT;

WHEN TOO_MANY_ROWS THEN


LV_CODE := SQLCODE;
LV_ERRMSG := SQLERRM;
INSERT INTO ERROR_LOG
VALUES
('SP_GET_SAL', LV_CODE, LV_ERRMSG, SYSDATE);
COMMIT;

WHEN ZERO_DIVIDE THEN


LV_CODE := SQLCODE;
LV_ERRMSG := SQLERRM;
INSERT INTO ERROR_LOG
VALUES
('SP_GET_SAL', LV_CODE, LV_ERRMSG, SYSDATE);
COMMIT;
WHEN VALUE_ERROR THEN
LV_CODE := SQLCODE;
LV_ERRMSG := SQLERRM;
INSERT INTO ERROR_LOG
VALUES
('SP_GET_SAL', LV_CODE, LV_ERRMSG, SYSDATE);
COMMIT;
WHEN CURSOR_ALREADY_OPEN THEN
LV_CODE := SQLCODE;
LV_ERRMSG := SQLERRM;
INSERT INTO ERROR_LOG
VALUES
('SP_GET_SAL', LV_CODE, LV_ERRMSG, SYSDATE);
COMMIT;

WHEN TIMEOUT_ON_RESOURCE THEN


LV_CODE := SQLCODE;
LV_ERRMSG := SQLERRM;
INSERT INTO ERROR_LOG
VALUES
('SP_GET_SAL', LV_CODE, LV_ERRMSG, SYSDATE);
COMMIT;
20

END;

WE CAN WRITE ANY NO OF BEGIN AND ENDS INSIDE BEGEN AND END

CREATE OR REPLACE PROCEDURE SP_EMP_BONUS_CAL AS

LN_BONUS NUMBER(10, 2);


CUR_BONUS EMP%ROWTYPE;
LN_BONUS_PER NUMBER(2);
BEGIN
FOR CUR_BONUS IN (SELECT * FROM EMP) LOOP
BEGIN
SELECT EB.BONUS_PER
INTO LN_BONUS_PER
FROM EMP_BONUS_PERCENTAGE EB
WHERE EB.DEPTNO = CUR_BONUS.DEPTNO;
LN_BONUS := (CUR_BONUS.SAL * LN_BONUS_PER) / 100;
EXCEPTION
WHEN NO_DATA_FOUND THEN
LN_BONUS := 999;
WHEN TOO_MANY_ROWS THEN
SELECT DISTINCT EB.BONUS_PER
INTO LN_BONUS_PER
FROM EMP_BONUS_PERCENTAGE EB
WHERE EB.DEPTNO = CUR_BONUS.DEPTNO;
LN_BONUS := (CUR_BONUS.SAL * LN_BONUS_PER) / 100;
END;

UPDATE EMP E SET E.NBONUS = LN_BONUS WHERE E.EMPNO = CUR_BONUS.EMPNO;

END LOOP;

COMMIT;
EXCEPTION
WHEN OTHERS THEN

ROLLBACK;
END;

USER DEFINED EXCEPTION: USER DEFINED EXCEPTIONS ARE TWO TYPES


RAISE AND RAISE_APPLICATION_ERROR
USER WILL RAISE ERROR BASED ON THEIR REQUIREMENT (USER WILL RAISE ERROR
BASED ON THEIR BUSINEES LOGIC)
RAISE :- DECLARATION SECTION IS REQUIRE AND EXCEPTION SECTION IS REQUIRE
IT WILL TERMINATE THE PROGRAM AND IT WILL GO TO THE EXCEPTION PART

RAISE_APPLICATION_ERROR: DECLARATION AND EXCEPTION HANDLING SECTION ARE


NOT REQUIRE

ERROR NUMBER WE CAN USE FROM : (- 20000 TO -20999)


EXAMPLES
CREATE OR REPLACE PROCEDURE SP_BONUS_CAL
AS
CURSOR EC IS SELECT * FROM EMP;
21

VEC EMP%ROWTYPE;

LN_BONUS NUMBER(10,2);
EX EXCEPTION ;
BEGIN
OPEN EC;
LOOP
FETCH EC INTO VEC ;
EXIT WHEN EC%NOTFOUND;

LN_BONUS := VEC.SAL * 20 /100;

IF LN_BONUS >= 1000 THEN


BEGIN
RAISE EX;
EXCEPTION
WHEN EX THEN
UPDATE EMP E SET E.BONUS = 500 WHERE
EMPNO = VEC.EMPNO;
END;
ELSE
UPDATE EMP E SET E.BONUS = LN_BONUS WHERE
EMPNO = VEC.EMPNO;
END IF;

END LOOP;
COMMIT;

END;

EXAMPLE 2
CREATE OR REPLACE PROCEDURE SP_BONUS_CAL_1
AS
CURSOR EC IS SELECT * FROM EMP;
VEC EMP%ROWTYPE;

LN_BONUS NUMBER(10,2);
-- EX EXCEPTION ;
BEGIN
OPEN EC;
LOOP
FETCH EC INTO VEC ;
EXIT WHEN EC%NOTFOUND;

LN_BONUS := VEC.SAL * 20 /100;

IF LN_BONUS >= 1000 THEN


RAISE_APPLICATION_ERROR(-20345,'THIS EMPLOYEE GOTE MORE THEN
1000 RS BONUS '||VEC.EMPNO);

ELSE
UPDATE EMP E SET E.BONUS = LN_BONUS WHERE
EMPNO = VEC.EMPNO;
END IF;
22

END LOOP;
COMMIT;

END;

NON PREDEFINED EXCEPTION(USER NAMED EXCEPTION) EXAMPLES


CREATE OR REPLACE PROCEDURE SP_NAMES AS
CURSOR CUR_NAMES IS
SELECT * FROM NAMES ORDER BY NAMES;--NAMES TABLE SHOULBE BE BEFORE CREATE THIS
PROCEDURE
EX EXCEPTION;
PRAGMA EXCEPTION_INIT(EX, -2299);
DX EXCEPTION;
PRAGMA EXCEPTION_INIT (DX, -2261);
LN_COUNT NUMBER;
BEGIN
FOR I IN CUR_NAMES LOOP
BEGIN
EXECUTE IMMEDIATE 'ALTER TABLE NAMES ADD CONSTRAINT UK_NAMES UNIQUE(NAMES)';
EXCEPTION
WHEN EX THEN
SELECT COUNT(*) INTO LN_COUNT FROM NAMES WHERE NAMES = I.NAMES;

IF LN_COUNT = 1 THEN
NULL;
ELSE
UPDATE NAMES N
SET NAMES = NAMES || '-' || 1
WHERE NAMES = I.NAMES
AND ROWID NOT IN
(SELECT MIN(ROWID) FROM NAMES NN WHERE NN.NAMES = N.NAMES);
COMMIT;
END IF;
WHEN DX THEN
RETURN;
END;
END LOOP;
END;
EXAMPLE 2

CREATE OR REPLACE PROCEDURE SP_BANK_LOAN_GEN AS

CURSOR CUR_LOAN IS
SELECT * FROM LOAN_INFO;

LV_STRING VARCHAR2(2000);
EX EXCEPTION;
PRAGMA EXCEPTION_INIT(EX, -1430);

LN_SEQ NUMBER;
LV_STR1 VARCHAR2(30);
LV_UPDATE_STR VARCHAR2(300);
BEGIN
23

LN_SEQ := SEQ_BLA_ID.NEXTVAL;
INSERT INTO BANK_LOAN_AMOUNT (ID) VALUES (LN_SEQ);
FOR VEC IN CUR_LOAN LOOP
LV_STRING := 'ALTER TABLE BANK_LOAN_AMOUNT ADD ' ||
REPLACE(VEC.LOAN_TYPE, ' ', '_') || ' NUMBER(15,2)';

BEGIN
EXECUTE IMMEDIATE LV_STRING;
EXCEPTION
WHEN EX THEN
NULL;
END;
LV_STR1 := REPLACE(VEC.LOAN_TYPE, ' ', '_');
LV_UPDATE_STR := 'UPDATE BANK_LOAN_AMOUNT BL SET ' || LV_STR1 || ' = ' ||
VEC.LOAN_AMOUNT || ' WHERE ID = ' || LN_SEQ;
EXECUTE IMMEDIATE LV_UPDATE_STR;

END LOOP;
COMMIT;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(SQLERRM);
ROLLBACK;
END;
DYNAMIC SQL:-
ORACLE WON’T ALLOW YOU TO WRITE DDL COMMANDS IN PL/SQL BLOCK IF YOU WANT
USE DDL COMMANDS IN PL/SQL BLOCK WE HAVE TO USE EXECUTE IMMEDIATE
COMMAND (EXECUTE IMMEDIATE IS A DYNAMIC SQL COMMAND)
EXAMPLES

CREATE OR REPLACE PROCEDURE SP_BANK_LOAN_GEN AS

CURSOR CUR_LOAN IS
SELECT * FROM LOAN_INFO;

LV_STRING VARCHAR2(2000);
EX EXCEPTION;
PRAGMA EXCEPTION_INIT(EX, -1430);

LN_SEQ NUMBER;
LV_STR1 VARCHAR2(30);
LV_UPDATE_STR VARCHAR2(300);
BEGIN
LN_SEQ := SEQ_BLA_ID.NEXTVAL;
INSERT INTO BANK_LOAN_AMOUNT (ID) VALUES (LN_SEQ);
FOR VEC IN CUR_LOAN LOOP
LV_STRING := 'ALTER TABLE BANK_LOAN_AMOUNT ADD ' ||
REPLACE(VEC.LOAN_TYPE, ' ', '_') || ' NUMBER(15,2)';

BEGIN
EXECUTE IMMEDIATE LV_STRING;
EXCEPTION
WHEN EX THEN
NULL;
END;
LV_STR1 := REPLACE(VEC.LOAN_TYPE, ' ', '_');
24

LV_UPDATE_STR := 'UPDATE BANK_LOAN_AMOUNT BL SET ' || LV_STR1 || ' = ' ||


VEC.LOAN_AMOUNT || ' WHERE ID = ' || LN_SEQ;
EXECUTE IMMEDIATE LV_UPDATE_STR;

END LOOP;
COMMIT;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(SQLERRM);
ROLLBACK;
END;
/

PRAGMA AUTONOMOUS_TRANSACTION :- PRAGMA AUTONOMOUS TRANSACTION


DEFINE AN INDEPENDENT TRANSACTION FROM IT’S PARENT TRANSACTION AND
ALLOW COMMIT ROLLBACK WITHOUT ANY EFFECTING OF PARENT TRANSACTION
--PENDING EXAMPLES
CREATE OR REPLACE PROCEDURE SP_EMP_UPDATE(P_OUT OUT VARCHAR2) AS
LN_EMPNO NUMBER;
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
SELECT EMPNO INTO LN_EMPNO FROM EMP WHERE DEPTNO = 10;
UPDATE EMP SET SAL = 500;
P_OUT := 'S';
EXCEPTION
WHEN OTHERS THEN
INSERT INTO ERROR_LOG
VALUES
('SP_EMP_UPDATE', '123', 'SOME ERROR', SYSDATE);
COMMIT;
P_OUT := 'F';
END;
/

CREATE OR REPLACE PROCEDURE SP_NEW_EMP AS


LV_STR VARCHAR2(2);
BEGIN
INSERT INTO EMP (EMPNO, DEPTNO) VALUES (3333, 20);
SP_EMP_UPDATE(LV_STR);
IF LV_STR = 'S' THEN
DELETE FROM DEPT WHERE DEPTNO = 30;
DBMS_OUTPUT.PUT_LINE('PROGRAM SUCCESS');
COMMIT;
ELSE
ROLLBACK;
END IF;
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
END;
25

BULK COLLET
PL/SQL ENGINE TELLS THE SQL ENGINE TO COLLECT ALL THE ROWS AT ONES AND PLACE
THEM INTO A COLLECTION VARIABLE (COMPOSITE DATA TYPE VARIABLE)

OR

SQL ENGINE GET THE DATA FROM THE DATABASE AND AT ONE SHOT ASSIGN WHOLE
DATA INTO COLLECTION VARIABLES

Composite Data Types (COLLECTIONS)


ASSOCIATIVE ARRAY (PL/SQL TABLE OR INDEXED BY TABLE):
1) WE CAN DELCLARE ASSOCIATIVE ARRAY ON COLLECTION OF ELEMENTS OR
SINGLE ELEMENT ( MEANS ASSOCIATIVE ARRAY WE CAN DECLARE ON TABLE ,
SYNONYM,VIEWS, RECORD OR ASSOCIATIVE ARRAY WE CAN DECLARE ON
SINGLE DATA TYPE LIKE NUMBER OR VARCHAR OR DATE..etc
2) EACH ELEMENT HAVE A INDEX NUMBER
SYNTAX:- TYPE <TYPE_NAME> IS TABLE OF <DATA_TYPE> INDEX BY
BINARY_INTEGER;

SYNTAX:-
TYPE TYPE_NAME IS TABLE OF {COLUMN_TYPE | VARIABLE%TYPE OR TABLE.COLUMN%TYPE}
[NOT NULL] OR TABLE.%ROWTYPE [INDEX BY BINARY_INTEGER];
IDENTIFIER TYPE_NAME;

-- PL/SQL TABLE EXAMPLE


CREATE OR REPLACE PROCEDURE SP_BULK_COLLECT AS
--PL/SQL TABLE EXAMPLE
TYPE TYP_EMP_DATA IS TABLE OF EMP%ROWTYPE INDEX BY BINARY_INTEGER;
TYP_EMP TYP_EMP_DATA;

BEGIN

SELECT * BULK COLLECT INTO TYP_EMP FROM EMP;

DBMS_OUTPUT.PUT_LINE('VARRAY EXAMPLES......');
DBMS_OUTPUT.PUT_LINE(' ');
FOR I IN 1 .. TYP_EMP.COUNT LOOP
DBMS_OUTPUT.PUT_LINE(TYP_EMP(I).ENAME);

END LOOP;
DBMS_OUTPUT.PUT_LINE('--------');
DBMS_OUTPUT.PUT_LINE(TYP_EMP(5).ENAME);
26

DBMS_OUTPUT.PUT_LINE('');
FOR I IN REVERSE 1 .. TYP_EMP.COUNT LOOP
DBMS_OUTPUT.PUT_LINE(TYP_EMP(I).ENAME);
END LOOP;
DBMS_OUTPUT.PUT_LINE('--------');
END SP_BULK_COLLECT;

VARRAY (VARIABLE SIZE ARRAYS):


1) VARRAY HAS MAX SIZE, AT THE TIME OF VARRAY DECLARATION WE HAVE TO
MENTION
2) THIS TYPE IS STORED INLINE WITH THE OTHER TABLE DATA
3) WE CAN CREATE VARRAY AS A SEPARATE TYPE OR WE CAN DECLARE VARRAY IN
PL/SQL BLOCK AS COMPOSIT DATA TYPE

--SIMPLE VARRAY EXAMPLE


CREATE OR REPLACE PROCEDURE SP_VARRAY AS
--VARRAY EXAMPLES
TYPE TYP_VARRAY IS VARRAY(30) OF NUMBER(15);
TYP_LV TYP_VARRAY;
--VARRAY
TYPE TYP_VR_COLORS IS VARRAY(4) OF VARCHAR2(30);
TYP_VARRAY_COLORS TYP_VR_COLORS := TYP_VR_COLORS
(‘RED’,’GREEN’,’YELLOW’,BLUE’);
BEGIN
SELECT SAL BULK COLLECT INTO TYP_LV FROM EMP;
DBMS_OUTPUT.PUT_LINE('VARRAY EXAMPLES......');
FOR I IN 1 .. TYP_LV.COUNT LOOP
DBMS_OUTPUT.PUT_LINE(TYP_LV(I));
END LOOP;
--COLORS
FOR I IN 1..TYP_VARRAY_COLORS.COUNT LOOP
DBMS_OUTPUT.PUT_LINE(TYP_VARRAY_COLORS(I));

END LOOP;
END SP_VARRAY;

NESTED TABLE:-
INITIALIZE NESTED TABLE BEHAVE LIKE SAME AS PL/SQL TABLE, WE CAN EXTEND AND
WE CAN STORE THE VALUES OR BY USING BULK COLLECT ALSO WE CAN STORE THE
RECORDS(VALUES)
UN-INITIALIZE NESTED TABLE WE CAN’T EXTEND BUT BY USING BULK COLLECT WE CAN
STORE THE RECORDS BUT NO PARTICULAR ORDER.
--UN INTIALIZED NESTED TABLE EXAMPLE
DECLARE
--UN-INTIALIZED NESTED TABLE
TYPE TYP_NESTED_TAB IS TABLE OF NUMBER;
TYP_NEST TYP_NESTED_TAB;
BEGIN
--WE CAN'T WRITE BELOW CODE FOR UN-INTIALIZED NESTED TABLE
/* TYP_NEST.EXTEND;
TYP_NEST(1) := 10;*/
27

--BUT WE CAN STORE THE INFORMATION BY USING BULK COLLECT


SELECT SAL BULK COLLECT INTO TYP_NEST FROM EMP;
FOR I IN 1..TYP_NEST.COUNT LOOP
DBMS_OUTPUT.PUT_LINE( TYP_NEST(I));
END LOOP;
END;

--INTIALIZED NESTED TABLE


DECLARE
--INTIALIZED NESTED TABLE
TYPE TYP_NESTED_TAB IS TABLE OF NUMBER;
TYP_NEST TYP_NESTED_TAB := TYP_NESTED_TAB();
BEGIN
--WE CAN WRITE
TYP_NEST.EXTEND;
TYP_NEST(1) := 10;
TYP_NEST.EXTEND;
TYP_NEST(2) := 2099;
DBMS_OUTPUT.PUT_LINE(TYP_NEST(2) || ' ' || TYP_NEST(1));
DBMS_OUTPUT.PUT_LINE(' ');
--WE CAN STORE THE INFORMATION BY USING BULK COLLECT
SELECT SAL BULK COLLECT INTO TYP_NEST FROM EMP;
FOR I IN 1 .. TYP_NEST.COUNT LOOP
DBMS_OUTPUT.PUT_LINE(TYP_NEST(I));
END LOOP;
END;
EXAMPLES:-SIMPLE NESTED TABLE
declare
TYPE TYP_NEST IS TABLE OF NUMBER;
TYP_EMP TYP_NEST;
BEGIN
SELECT SAL BULK COLLECT INTO TYP_EMP FROM EMP;
FOR I IN 1..TYP_EMP.COUNT LOOP
DBMS_OUTPUT.PUT_LINE(TYP_EMP(I));
END LOOP;
END;

CONVERTING NESTED TABLE INTO PLSQL TABLE

declare
TYPE TYP_NEST IS TABLE OF EMP%ROWTYPE;
TYP_EMP TYP_NEST:=TYP_NEST();
BEGIN
SELECT * BULK COLLECT INTO TYP_EMP FROM EMP;
FOR I IN 1..TYP_EMP.COUNT LOOP
DBMS_OUTPUT.PUT_LINE(TYP_EMP(I).EMPNO||TYP_EMP(i).ENAME);
END LOOP;
END;

RECORD TYPE :-
28

RECORD CONSIST OF DIFFERENT FIELDS (MEANS : COLLECTION OF DIFFERENT FIELDS


AND STORED AT ONE LOCATION)

WHERE CAN WE USE RECORD TYPE ?:-


1) WHEN WE WANT TO SELECT SOME FIELDS FROM A TABLE OR WHEN WE WANT TO
SELECT DI FFERENT FIELDS ROM DIFFERENT TABLES THEN WE CAN USE RECORD TYPE.
2) WE CAN STORE ONLY ONE RECORD (ROW) AT A TIME , IT WON’T SUPPORT TO STORE
MULTIPLE ROWS (IT WON’T SUPPORT BULK COLLECT CLAUSE)
3) IF YOU WANT STORE MULTIPLE ROWS IN RECORD TYPE VARIABLE THEN YOU HAVE
TO CREATE PL/SQL TABLE OR NESTED TABLE ON THAT RECORD TYPE ;

SYNTAX:
TYPE EMP_RECORD_TYPE IS RECORD
(EMPLOYEE_ID
NUMBER(6) NOT NULL := 100,
LAST_NAME EMPLOYEES.LAST_NAME%TYPE,
JOB_ID EMPLOYEES.JOB_ID%TYPE);
EMP_RECORD EMP_RECORD_TYPE;

EXAMPLE:
DECLARE
TYPE TYP_RECORD IS RECORD (EMPNO NUMBER, ENAME VARCHAR2(25), SAL NUMBER,
DNAME VARCHAR2(30), LOC VARCHAR2(30));
TYP_REC TYP_RECORD;
BEGIN
SELECT EMPNO, ENAME, SAL, DNAME , LOCATION INTO TYP_REC FROM EMP E, DEPT D
WHERE E.DEPTNO = D.DEPTNO AND E.ENAME =’ SMITH’ ;
DBMS_OUTPUT.PUT_LINE(TYP_REC.EMPNO || TYP_REC.ENAME||TYP_REC.LOC);
END;
EXAMPLE 2
CREATE OR REPLACE PROCEDURE SP_RECORD_TYPE_EXP AS
TYPE TYP_REC IS RECORD(
L_EMPNO NUMBER,
L_ENAME EMP.ENAME%TYPE,
SAL NUMBER(10, 2),
DNAME VARCHAR2(30),
LOCATION VARCHAR2(30));
--THIS IS FOR FETCHING SIGNLE RECORD
L_TYP_REC TYP_REC;
--WANT TO FETCH MULTIPLE RECORDS THEN NEED PL/SQL TABLE ON RECORD TYPE

TYPE TYP_TAB_EMP IS TABLE OF TYP_REC INDEX BY BINARY_INTEGER;

TYP_EMP TYP_TAB_EMP;

BEGIN
-- FOR SINGLE RECORD FETCHING BY USING RECORD TYPE
SELECT E.EMPNO, E.ENAME, E.SAL, D.DNAME, D.LOC
INTO L_TYP_REC
FROM EMP E, DEPT D
WHERE E.DEPTNO = D.DEPTNO
29

AND E.EMPNO = 7369;


DBMS_OUTPUT.PUT_LINE(L_TYP_REC.L_EMPNO || ' ' || L_TYP_REC.LOCATION);

-- FOR MULTIPLE RECORDS FETCHING


DBMS_OUTPUT.PUT_LINE('------------- PL/SQL TABLE OF RECORD TYPE');
SELECT E.EMPNO, E.ENAME, E.SAL, D.DNAME, D.LOC BULK COLLECT
INTO TYP_EMP
FROM EMP E, DEPT D
WHERE E.DEPTNO = D.DEPTNO;
FOR I IN 1 .. TYP_EMP.COUNT LOOP
DBMS_OUTPUT.PUT_LINE(TYP_EMP(I).L_EMPNO || ' ' || TYP_EMP(I).LOCATION);

END LOOP;
END;
SOME EXAMPLES:(BY ANALYTICAL FUNCTIONS)
DECLARE
TYPE TYP_REC IS RECORD(
EMPNO NUMBER,
HIG_SAL NUMBER,
DEPTNO NUMBER);
TYPE TYP_TAB IS TABLE OF TYP_REC INDEX BY BINARY_INTEGER;
TYP_1 TYP_TAB;
BEGIN
SELECT EMPNO, SAL, DEPTNO BULK COLLECT
INTO TYP_1
FROM (SELECT EMPNO,
SAL,
DEPTNO,
RANK() OVER(PARTITION BY DEPTNO ORDER BY SAL DESC) RNK
FROM EMP)
WHERE RNK = 2;

FOR I IN 1 .. TYP_1.COUNT LOOP


DBMS_OUTPUT.PUT_LINE(TYP_1(I).HIG_SAL);
END LOOP;
END;

COLLECTION EXAMPLES
CREATE OR REPLACE PROCEDURE SP_BULK_COLLECT AS
--PL/SQL TABLE EXAMPLE
TYPE TYP_EMP_DATA IS TABLE OF EMP%ROWTYPE INDEX BY BINARY_INTEGER;
TYP_EMP TYP_EMP_DATA;
--VARRAY EXAMPLES

TYPE TYP_VARRAY IS VARRAY(30) OF NUMBER(15);


TYP_LV TYP_VARRAY;

BEGIN

SELECT * BULK COLLECT INTO TYP_EMP FROM EMP;


SELECT SAL BULK COLLECT INTO TYP_LV FROM EMP;
30

DBMS_OUTPUT.PUT_LINE('VARRAY EXAMPLES......');
FOR I IN 1 .. TYP_LV.COUNT LOOP
DBMS_OUTPUT.PUT_LINE(TYP_LV(I));
END LOOP;
DBMS_OUTPUT.PUT_LINE(' ');
FOR I IN 1 .. TYP_EMP.COUNT LOOP
DBMS_OUTPUT.PUT_LINE(TYP_EMP(I).ENAME);

END LOOP;
DBMS_OUTPUT.PUT_LINE('--------');
DBMS_OUTPUT.PUT_LINE(TYP_EMP(5).ENAME);

DBMS_OUTPUT.PUT_LINE('');
FOR I IN REVERSE 1 .. TYP_EMP.COUNT LOOP
DBMS_OUTPUT.PUT_LINE(TYP_EMP(I).ENAME);
END LOOP;
DBMS_OUTPUT.PUT_LINE('--------');
END SP_BULK_COLLECT;
--------------collection very imp programe
CREATE OR REPLACE PROCEDURE SP_IMP_COLLECTIONS AS
TYPE TYP_TAB IS TABLE OF NUMBER(10) INDEX BY BINARY_INTEGER;

TYP_SAL TYP_TAB;
TYP_PF TYP_TAB;
TYP_BONUS TYP_TAB;
TYP_HRA TYP_TAB;
TYP_EMPNO TYP_TAB;
BEGIN
SELECT SAL,
(SAL * 20 / 100),
(SAL * 30 / 100),
(SAL * 40 / 100),
EMPNO BULK COLLECT
INTO TYP_SAL, TYP_PF, TYP_BONUS, TYP_HRA, TYP_EMPNO
FROM EMP;

DBMS_OUTPUT.PUT_LINE('EMPNO ' || 'SALARY ' || ' PF' || ' BONUS');


FOR I IN 1 .. TYP_PF.COUNT LOOP

DBMS_OUTPUT.PUT_LINE(TYP_EMPNO(I) || ' ' || TYP_SAL(I) || ' ' ||


TYP_PF(I) || ' ' || TYP_BONUS(I));
END LOOP;
END;

METHOD DESCRIPTION
EXISTS(N) RETURNS TRUE IF THE NTH ELEMENT IS EXISTS IN A COLLECTION
COUNT RETURNS THE NUMBER OF ELEMENTS THAT A COLLECTION
CURRENTLY CONTAINS.
FIRST LAST RETURNS THE FIRST AND LAST (SMALLEST AND LARGEST) INDEX
NUMBERS IN A PL/SQL
TABLE. RETURNS NULL IF THE PL/SQL TABLE IS EMPTY.
PRIOR(N) RETURNS THE INDEX NUMBER THAT PRECEDES INDEX N
NEXT(N) RETURNS THE INDEX NUMBER THAT SUCCEEDS INDEX N
31

EXTEND(N,I) INCREASES THE SIZE OF A PL/SQL TABLE OR NESTED TABLE.

EXTEND APPENDS ONE NULL ELEMENT TO A PL/SQL TABLE OR NESTED TABLE.

EXTEND(N) APPENDS N NULL ELEMENTS TO A PL/SQL TABLE OR NESTED TABLE.

EXTEND(N, I) APPENDS N COPIES OF THE I TH ELEMENT TO A COLLECTION

TRIM* TRIM REMOVES ONE ELEMENT FROM THE END OF A COLLECTION

TRIM(N) REMOVES N ELEMENTS FROM THE END OF A COLLECTION

DELETE DELETE REMOVES ALL ELEMENTS FROM A COLLECTION

DELETE(N) REMOVES THE N TH ELEMENT FROM A COLLECTION

DELETE(M, N) REMOVES ALL ELEMENTS IN THE RANGE , M ... N FROM A COLLECTION

LIMIT GIVES MAXIMUM LIMIT OF VARRAY, FOR NESTED TABLE AND PL/SQL
TABLE IT GIVES NULL
IMPORTANT POINTS:-
EXTEND:-
EXTEND METHOD WON’T SUPPORT FOR UNINITIALIZED NESTED TABLE AND
VARRAY TABLE.
EXTEND METHOD IS NOT REQIURE FOR PLSQL TABLE.
EXTEND IS USED FOR WHEN WE ARE MANUALLY INSERTING VALUES IN
INTIALIZED NESTED TABLE AND VARRAY TABLE.
EXAMPLE:-
DECLARE
--NESTED TABLE
TYPE TYP_EXISTS IS TABLE OF NUMBER;
TYP_TEST TYP_EXISTS := TYP_EXISTS();
---PL/SQL TABLE
TYPE TYP_TAB IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;
TYP_T TYP_TAB;
--VARRAY
TYPE TYP_VAR IS VARRAY(10) OF NUMBER;
TYP_V TYP_VAR := TYP_VAR();
BEGIN
--NESTED TABLE
TYP_TEST.EXTEND;
TYP_TEST(1) := 200;
DBMS_OUTPUT.PUT_LINE (TYP_TEST(1));
--PL_SQL TABLE
TYP_T(1) := 10;
--VARRAY
TYP_V.EXTEND;
TYP_V(1) := 20;
LIMIT METHOD:-
32

LIMIT METHOD ALWAYS WILL RETURN NULL FOR NESTED TABLE AND PLSQL
TABLE BECAUSE THERE IS NO UN BOUNDED OR MAXLIMIT.
LIMIT METHOD WILL GIVE VALUE FOR VARRAY BECAUSE IT HAD A MAX
LIMIT.
EXIST METHOD:-
EXISTS METHOD WILL SUPPORT ALL COLLECTION DATATYPES.
IT RETURNS TRUE OR FALSE IF INDEX NUMBER EXISTS IT RETURNS TRUE
ELSE FALSE.
DELETE METHOD:-
DELETE METHOD WONT SUPPORT IN VARRAY WHEN WE ARE DELETING
PARTICULAR DATA.BUT IT WILL SUPPORT TO DELETE COMPLETE DATA IN
VARRAY.
DELETE METHOD IS SUPPORTED USED TO DELETE DATA BETWEEN RANGES
IN PLSQL TABLE AND NESTED TABLE.
TRIM METHOD:-
TRIM WONT SUPPORT FOR PLSQL TABLE.
TRIM DELETES THE LAST RECORD.
TRIM(3) IT DELETES THE LAST THREE RECORDS.
IF COLLECTION DID NOT FOUND RECORD IT GIVES NODATAFOUND.
FIRST:-IT GIVES THE FIRST INDEX NUMBER.
LAST:-IT GIVES THE LAST INDEX NUMBER.
COUNT:-IT GIVES THE COUNT OF RECORDS.

COLLECTION METHODS
LIMIT METHOD:
LIMIT METHOD WE CAN USE FOR VARRAY ONLY, IT WILL GIVE MAXIMUM LIMIT OF
VARRAY
FOR PL/SQL TABLE AND NESTED TABLE IT WILL GIVE NULL .(THESE ARE UNBOUNDED)

EX:-
DECLARE
--VARRAY
TYPE TYP_VARRAY IS VARRAY(3) OF NUMBER;
TYP_VAR TYP_VARRAY := TYP_VARRAY(100,200,300);

--TYPE PL/SQL TABLE


TYPE TYP_PLSQL_TAB IS TABLE OF EMP%ROWTYPE INDEX BY BINARY_INTEGER;
TYP_TAB TYP_PLSQL_TAB;

--NESTED TABLE
TYPE TYP_NEST_TAB IS TABLE OF EMP%ROWTYPE INDEX BY BINARY_INTEGER;
TYP_NEST TYP_NEST_TAB;

BEGIN
DBMS_OUTPUT.PUT_LINE( 'PLSQL TAB '||TYP_TAB .LIMIT ||' NESTED TAB '||
TYP_NEST.LIMIT||' VARRAY '|| TYP_VAR.LIMIT);

END;
EXISTS METHOD:-
33

EXISTS:- RETURNS TRUE IF THE Nth ELEMENT IS EXISTS IN A COLLECTION, OTHERWISE


EXISTS(N) RETUNS FALSE:

DECLARE
TYPE TYP_VARRAY IS VARRAY(3) OF NUMBER;
TYP_VAR TYP_VARRAY := TYP_VARRAY(100, 200, 300);

--TYPE PL/SQL TABLE


TYPE TYP_PLSQL_TAB IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;
TYP_TAB TYP_PLSQL_TAB;

--NESTED TABLE
TYPE TYP_NEST_TAB IS TABLE OF NUMBER;
TYP_NEST TYP_NEST_TAB := TYP_NEST_TAB(111, 222, 333, 444);
BEGIN
--VARRAY
IF TYP_VAR.EXISTS(3) THEN
TYP_VAR(3) := 999;
DBMS_OUTPUT.PUT_LINE(TYP_VAR(3));
END IF;
---PL/SQL TAB THIS IS FAILED BECAUSE NO RECORDS IN PL/SQL TABLE DATATYPE
IF TYP_TAB.EXISTS(1) THEN
TYP_TAB(1) := 888;
DBMS_OUTPUT.PUT_LINE(TYP_TAB(1));
END IF;
--NESTED TABLE
IF TYP_NEST.EXISTS(3) THEN
TYP_NEST(3) := 666;
DBMS_OUTPUT.PUT_LINE(TYP_NEST(3));

END IF;
END;
PRIOR METHOD:- RETURNS THE INDEX NUMBER THAT PRECEDES INDEX N
SYNTAX :- PRIOR(N)

DECLARE
TYPE TYP_VARRAY IS VARRAY(3) OF NUMBER;
TYP_VAR TYP_VARRAY := TYP_VARRAY(100, 200, 300);

--TYPE PL/SQL TABLE


TYPE TYP_PLSQL_TAB IS TABLE OF EMP%ROWTYPE INDEX BY BINARY_INTEGER;
TYP_TAB TYP_PLSQL_TAB;

--NESTED TABLE
TYPE TYP_NEST_TAB IS TABLE OF NUMBER;
TYP_NEST TYP_NEST_TAB := TYP_NEST_TAB(111, 222, 333, 444);
BEGIN
DBMS_OUTPUT.PUT_LINE( 'NESTED TABLE EXAMPLES....');
--VARRAY
DBMS_OUTPUT.PUT_LINE(TYP_VAR.PRIOR(3));
DBMS_OUTPUT.PUT_LINE(TYP_VAR.PRIOR(2));

DBMS_OUTPUT.PUT_LINE( 'PL/SQL TABLE EXP....');


SELECT * BULK COLLECT INTO TYP_TAB FROM EMP;
FOR I IN 1..TYP_TAB.COUNT LOOP
34

DBMS_OUTPUT.PUT_LINE(TYP_TAB.PRIOR(I));
END LOOP;
--NESTED TABLE
DBMS_OUTPUT.PUT_LINE( 'NESTED TABLE EXP-----');

DBMS_OUTPUT.PUT_LINE(TYP_NEST.PRIOR(3));
DBMS_OUTPUT.PUT_LINE(TYP_NEST.PRIOR(4));

END;
NEXT METHOD:- RETURNS THE INDEX NUMBER THAT SUCCEEDS INDEX N

SYNTAX :- NEXT(N)

DECLARE
TYPE TYP_VARRAY IS VARRAY(3) OF NUMBER;
TYP_VAR TYP_VARRAY := TYP_VARRAY(100, 200, 300);

--TYPE PL/SQL TABLE


TYPE TYP_PLSQL_TAB IS TABLE OF EMP%ROWTYPE INDEX BY BINARY_INTEGER;
TYP_TAB TYP_PLSQL_TAB;

--NESTED TABLE
TYPE TYP_NEST_TAB IS TABLE OF NUMBER;
TYP_NEST TYP_NEST_TAB := TYP_NEST_TAB(111, 222, 333, 444);
BEGIN
DBMS_OUTPUT.PUT_LINE('VARRAY TABLE EXAMPLES....');
--VARRAY
DBMS_OUTPUT.PUT_LINE(TYP_VAR.NEXT(3));
DBMS_OUTPUT.PUT_LINE(TYP_VAR.NEXT(2));

DBMS_OUTPUT.PUT_LINE('PL/SQL TABLE EXP....');


SELECT * BULK COLLECT INTO TYP_TAB FROM EMP;
FOR I IN 1 .. TYP_TAB.COUNT LOOP
DBMS_OUTPUT.PUT_LINE(TYP_TAB.NEXT(I));
END LOOP;
--NESTED TABLE
DBMS_OUTPUT.PUT_LINE('NESTED TABLE EXP-----');

DBMS_OUTPUT.PUT_LINE(TYP_NEST.NEXT(2));
DBMS_OUTPUT.PUT_LINE(TYP_NEST.NEXT(3));

END;

COUNT METHOD:- RETURNS THE NUMBER OF ELEMENTS THAT A COLLECTION CURRENTLY


CONTAINS.
FIRST AND LAST METHODS :- RETURNS THE FIRST AND LAST (SMALLEST AND LARGEST) INDEX NUMBERS
IN A PL/SQL TABLE. RETURNS NULL IF THE PL/SQL TABLE IS EMPTY.
COUNT LAST
IT WILL GIVE NUMBER OF ELEMENTS IN A IT WILL GIVE LARGEST INDEX NUMBER
COLLECTION (EX: SUPPOSE COLLECTION HAVING 5 RECORDS, IN
(EX: SUPPOSE COLLECTION HAVING 5 RECORDS, IN THAT 3RD RECORD DELETED BY USING DELETE
THAT 3RD RECORD DELETED BY USING DELETE METHOD THEN LAST WILL GIVE 5)
METHOD THEN COUNT WILL GIVE 4)
35

EXAMPLES OF COUNT, FIRST AND LAST METHODS:-


DECLARE
TYPE TYP_VARRAY IS VARRAY(3) OF NUMBER;
TYP_VAR TYP_VARRAY := TYP_VARRAY(100, 200, 300);

--TYPE PL/SQL TABLE


TYPE TYP_PLSQL_TAB IS TABLE OF EMP%ROWTYPE INDEX BY BINARY_INTEGER;
TYP_TAB TYP_PLSQL_TAB;

--NESTED TABLE
TYPE TYP_NEST_TAB IS TABLE OF NUMBER;
TYP_NEST TYP_NEST_TAB := TYP_NEST_TAB(111, 222, 333, 444);
BEGIN
DBMS_OUTPUT.PUT_LINE('VARRAY TABLE EXAMPLES....');
--VARRAY
DBMS_OUTPUT.PUT_LINE(TYP_VAR.COUNT);
DBMS_OUTPUT.PUT_LINE(TYP_VAR.LAST);

--TYP_VAR.DELETE(3);
DBMS_OUTPUT.PUT_LINE(TYP_VAR.COUNT);
DBMS_OUTPUT.PUT_LINE(TYP_VAR.LAST);

--PL/SQL TABLE
DBMS_OUTPUT.PUT_LINE('PL/SQL TABLE EXP....');
SELECT * BULK COLLECT INTO TYP_TAB FROM EMP;
DBMS_OUTPUT.PUT_LINE(TYP_TAB.LAST);
DBMS_OUTPUT.PUT_LINE(TYP_TAB.COUNT);
TYP_TAB.DELETE(3);
DBMS_OUTPUT.PUT_LINE(TYP_TAB.LAST);
DBMS_OUTPUT.PUT_LINE(TYP_TAB.COUNT);
DBMS_OUTPUT.PUT_LINE('PL/SQL TABLE LOOP EXP....');
-- BELOW FOR LOOP WILL FAIL BECAUSE MIDDLE REOCRDS WE DELETED
/* FOR I IN 1 .. TYP_TAB.COUNT LOOP
DBMS_OUTPUT.PUT_LINE(TYP_TAB(I).EMPNO);
END LOOP;
*/
--NESTED TABLE
DBMS_OUTPUT.PUT_LINE('NESTED TABLE EXP-----');

DBMS_OUTPUT.PUT_LINE(TYP_NEST.COUNT);
DBMS_OUTPUT.PUT_LINE(TYP_NEST.LAST);
TYP_NEST.DELETE(3);
DBMS_OUTPUT.PUT_LINE(TYP_NEST.COUNT);
DBMS_OUTPUT.PUT_LINE(TYP_NEST.LAST);

END;
DELETE METHOD:-
DELETE :- REMOVES ALL ELEMENTS FROM A COLLECTION
DELETE (N):- REMOVES THE N TH ELEMENT FROM A COLLECTION
DELETE (M,N):- REMOVES ALL ELEMENTS IN THE RANGE , M ... N FROM A COLLECTION

DECLARE
TYPE TYP_NEST_TAB IS TABLE OF NUMBER;
TYP_NEST TYP_NEST_TAB := TYP_NEST_TAB(111, 222, 333, 444,5555,66666,77777,88,99,00);
BEGIN
36

--DELETE M..N
TYP_NEST.DELETE(8,10); --IT WILL DELETE 88 TO 00
FOR I IN 1..TYP_NEST.COUNT LOOP
DBMS_OUTPUT.PUT_LINE( TYP_NEST(I));
END LOOP;
DBMS_OUTPUT.PUT_LINE( ' DELETE PARTICULAR RECORD...');
TYP_NEST.DELETE(6); --IT WILL DELETE 6TH RECORD ONLY, BELOW LOOP WILL FAIL
/*FOR I IN 1..TYP_NEST.COUNT LOOP
DBMS_OUTPUT.PUT_LINE( TYP_NEST(I));
END LOOP;
*/
DBMS_OUTPUT.PUT_LINE( 'DELETE ALL THE RECORDS');
TYP_NEST.DELETE;
END;
TRIM METHOD:-
TRIM :- TRIM REMOVES ONE ELEMENT FROM THE END OF A COLLECTION
TRIM (N) :- REMOVES N ELEMENTS FROM THE END OF A COLLECTION
NOTE :- TRIM WON’T SUPPORT PL/SQL TABLE TYPE
DECLARE
TYPE TYP_NEST_TAB IS TABLE OF NUMBER;
TYP_NEST TYP_NEST_TAB := TYP_NEST_TAB(111, 222, 333, 444,5555,66666,77777,88,99,00);
BEGIN
--TRIM
TYP_NEST.TRIM; --IT WILL DELETE LAST RECORD
FOR I IN 1..TYP_NEST.COUNT LOOP
DBMS_OUTPUT.PUT_LINE( TYP_NEST(I));
END LOOP;
DBMS_OUTPUT.PUT_LINE( 'IT WILL DELETE LAST 4 RECORDS');
TYP_NEST.TRIM(4); --IT WILL DELETE LAST RECORD
FOR I IN 1..TYP_NEST.COUNT LOOP
DBMS_OUTPUT.PUT_LINE( TYP_NEST(I));
END LOOP;
END;

BULK BIND (FORALL)


ORACLE USES TWO ENGINES TO PROCESS PL/SQL CODE.
ALL PROCEDURE CODE IS HANDELED BY THE PL/SQL ENGINE WHILE ALL SQL IS HANDELED BY THE SQL
ENGINE.
IF YOU WRITE ANY DML OPERATION INSIDE THE COLLECTION FOR LOOP FOR EACH STATEMENT IT IS
CONSIDER AS A SEPARATE STATEMENT. SO FOR EACH STATEMENT EXECUTION PURPOSE IT WILL CREATE
SEPARATE CONTEXT SWITCHESS BETWEEN THE PL/SQL ENGINE AND SQL ENGINE. TO AVOID THAT WE
CAN USE BULK BIND CONCEPT.
THEN WHAT BULK BIND WILL DO , IT WILL WAIT UNTIL THE LOOP END THEN BIND ALL THE DML
STATEMENTS AND AT ONE SHOT IT WILL SEND TO SQL ENGINE .
EXAMPLES
CREATE OR REPLACE PROCEDURE SP_LIMIT AS
TYPE TYP_EMP IS TABLE OF EMP%ROWTYPE INDEX BY BINARY_INTEGER;
TYP_LIMIT TYP_EMP;
BEGIN
37

SELECT * BULK COLLECT INTO TYP_LIMIT FROM EMP;


--BULKBIND MEANS FORALL
FORALL I IN 1 .. TYP_LIMIT.COUNT
INSERT INTO DUM_EMP VALUES TYP_LIMIT (I);

COMMIT;
END SP_LIMIT;

BULK LIMIT
PL/SQL COLLECTIONS ARE IN MEMORY, SO MASSIVE COLLECTIONS CAN HAVE A EFFECT ON SYSTEM
PERFORMANCE DUE TO AMOUNT OF MEMORY REUIRE.
TO AVOID THAT WE CAN USE BULK LIMIT CLAUSE. THEN WHAT BULK LIMIT CLAUSE WILL DO. IT WILL
SPLIT THE COLLECTION INTO CHUNKS OF 1000 OR 5000 OR… etc. PROCESSING EACH CHUNK IN TURN
(NOTE: 1) THE USE OF EXPLICIT CURSOR FOR THIS BULK LIMIT OPERATION
NOTE :2) DON’T USE THIS COMMAND TO COME OUT FROM THE CURSOR
EXIT WHEN (CURSOR_NAME%NOT FOUND;
USE THIS COMMAND ONLY :- EXIT WHEN (COLLECTION_NAME.COUNT =0);
EXAMPLE
CREATE OR REPLACE PROCEDURE SP_BULK_LIMIT AS
CURSOR C1 IS
select * from EMP;

TYPE TYP_T IS TABLE OF EMP%ROWTYPE INDEX BY BINARY_INTEGER;


TYP_EMP TYP_T;
BEGIN

OPEN C1;
LOOP
FETCH C1 BULK COLLECT
--BULK LIMIT + BULK COLLECT + BULK BIND + CURSOR
INTO TYP_EMP LIMIT 1000;
EXIT WHEN(TYP_EMP.COUNT = 0);
FORALL I IN 1 .. TYP_EMP.COUNT
INSERT INTO AUDIT_EMP VALUES TYP_EMP (I);
END LOOP;
CLOSE C1;
COMMIT;
END SP_BULK_LIMIT;
EXAMPLE
CREATE OR REPLACE PROCEDURE SP_BULK_LIMIT_1 AS
CURSOR C1 IS
select EMPNO, ENAME from EMP;

TYPE TYP_ENO IS TABLE OF EMP.EMPNO%TYPE INDEX BY BINARY_INTEGER;


TYP_EMPNO TYP_ENO;
TYPE TYP_ENM IS TABLE OF EMP.ENAME%TYPE INDEX BY BINARY_INTEGER;
TYP_ENAME TYP_ENM;
BEGIN

OPEN C1;
LOOP
FETCH C1 BULK COLLECT
INTO TYP_EMPNO, TYP_ENAME LIMIT 1000;
--BULK LIMIT + BULK COLLECT + BULK BIND + CURSOR
EXIT WHEN(TYP_EMPNO.COUNT = 0);
38

FORALL I IN 1 .. TYP_EMPNO.COUNT
UPDATE AUDIT_EMP AU
SET AU.ENAME = TYP_ENAME(I)
WHERE AU.EMPNO = TYP_EMPNO(I);
END LOOP;
CLOSE C1;
COMMIT;
END SP_BULK_LIMIT_1;

PACKAGE USES
1) PACKAGE ALLOWS US TO ORGANISE OUR APPLICATION DEVELOPMENT MORE
EFFECIENTLY (MEANS: IF YOU ARE CALLING ANY PACKAGED PROCEDURE THEN
ENTIRE PACKAGE WILL COME AND STORE IN THE RAM IF YOU ARE CALLING
ANOTHER PROCEDURE THEN NO NEED TO GO AND SEARCH IN THE DATABASE BECAUSE
THAT IS ALSO ALREADY EXIST IN THAT PACKAGE SO IMMEDIATELY IT WILL
EXECUTE)
2) PACKAGE CONTAIN GLOBAL VARIABLES, RECORDS, CURSORS, PROCEDURES,
FUNCTIONS THOSE WE CAN USE INSIDE THE PACKAGE BODY OR WE CAN USE OUT
SIDE THE PACKAGE.
3) FUNCTION OVERLOADING (MEANS WE CAN CREATE ONE OR MORE PROCEDURES OR
FUNCTIONS WITH SAME NAME, BUT HERE WE HAVE TO REMBER ONE THING.
NUMBER OF PARAMETERS SHOULD BE DIFFERENT)
4) RELATED OBJECTS WE CAN STORE IN ONE AREA
5) WITHOUT BODY WE CAN CREATE PACKAGE SPECIFICATION, WHAT ARE THERE IN THE
SPEC THOSE ARE CALLED GLOBAL
6) IF YOU DROP PACKAGE BOTH SPEC, BODY WILL DROP, WE CAN’T DROP SEPARATELY

EXAMPLES:
PACKAGE_SPECIFICATION
CREATE OR REPLACE PACKAGE PKG_TEST AS
G_DATE DATE := SYSDATE;

PROCEDURE SP_RESULT(P1 NUMBER,


P2 NUMBER,
P_SUM OUT NUMBER,
P_MUL OUT NUMBER);

END;
PACKAGE_BODY:
CREATE OR REPLACE PACKAGE BODY PKG_TEST AS

PROCEDURE SP_SUM_OF_NUMBERS(P_NUM1 NUMBER,


P_NUM2 NUMBER,
P_OUT_SUM OUT NUMBER) AS
LN_SUM NUMBER;
BEGIN
39

LN_SUM := P_NUM1 + P_NUM2;


P_OUT_SUM := LN_SUM;
END;

PROCEDURE SP_SMULT_OF_NUMBERS(P_NUM1 NUMBER,


P_NUM2 NUMBER,
P_OUT_MUL OUT NUMBER) AS
LN_MULT NUMBER;
BEGIN
LN_MULT := P_NUM1 * P_NUM2;
P_OUT_MUL := LN_MULT;
END;

PROCEDURE SP_RESULT(P1 NUMBER,


P2 NUMBER,
P_SUM OUT NUMBER,
P_MUL OUT NUMBER,
P_OUT_TODAY OUT DATE) AS

BEGIN
SP_SUM_OF_NUMBERS(P1, P2, P_SUM);
SP_SMULT_OF_NUMBERS(P1, P2, P_MUL);
P_OUT_TODAY := G_DATE;
END;

PROCEDURE SP_RESULT(P1 NUMBER,


P2 NUMBER,
P_SUM OUT NUMBER,
P_MUL OUT NUMBER) AS
BEGIN
SP_SUM_OF_NUMBERS(P1, P2, P_SUM);
SP_SMULT_OF_NUMBERS(P1, P2, P_MUL);
END;

END;
-- PACKAGE SPEC:

CREATE OR REPLACE PACKAGE PKG_GLOBAL_TYPES AS


TYPE G_TYP IS TABLE OF EMP%ROWTYPE INDEX BY BINARY_INTEGER;
CURSOR G_CUR IS
select * from DEPT;

G_TYP_EMP G_TYP;

END PKG_GLOBAL_TYPES;
/
--USING GLOBAL CURSORS OR TYPES INSIDE ANOTHER OBJECT
CREATE OR REPLACE PROCEDURE SP_GLOBAL_PKG_CALL AS
BEGIN
select * BULK COLLECT INTO PKG_GLOBAL_TYPES.G_TYP_EMP from EMP;

FOR I IN 1 .. PKG_GLOBAL_TYPES.G_TYP_EMP.COUNT LOOP


DBMS_OUTPUT.put_line(PKG_GLOBAL_TYPES.G_TYP_EMP(I).EMPNO);
DBMS_OUTPUT.put_line(PKG_GLOBAL_TYPES.G_TYP_EMP(I).ENAME);
DBMS_OUTPUT.put_line('');
END LOOP;
END SP_GLOBAL_PKG_CALL;
40

/
EXAMPLE 2:
CREATE OR REPLACE PROCEDURE SP_PKG_GLOBAL_TYP_CALL AS
TYP_EMP PKG_GLOBAL_TYPES.G_TYP; --GLOBAL TYP

VEC DEPT%ROWTYPE;
BEGIN
select * BULK COLLECT INTO TYP_EMP from EMP;
--COLLECTION
DBMS_OUTPUT.PUT_LINE('COLLECTION OUTPUT-----------');
FOR I IN 1 .. TYP_EMP.COUNT LOOP
DBMS_OUTPUT.put_line(TYP_EMP(I).EMPNO);
DBMS_OUTPUT.put_line(TYP_EMP(I).ENAME);
DBMS_OUTPUT.put_line('');
END LOOP;
--GLOBAL CURSOR
DBMS_OUTPUT.PUT_LINE('CURSOR OUTPUT');
OPEN PKG_GLOBAL_TYPES.G_CUR;
LOOP
FETCH PKG_GLOBAL_TYPES.G_CUR
INTO VEC;
EXIT WHEN(PKG_GLOBAL_TYPES.G_CUR%NOTFOUND);
DBMS_OUTPUT.PUT_LINE(VEC.DEPTNO || ' ' || VEC.DNAME);
END LOOP;
CLOSE PKG_GLOBAL_TYPES.G_CUR;
--
END SP_PKG_GLOBAL_TYP_CALL;

PRAGMA SERIALLY_REUSABLE:
GENARALLY IF YOU CALL ANY PACKAGED PROCEDURE OR PACKAGED FUNCTION OR PACKAGED
GLOBAL VARIABLE THEN ENTIRE PACKAGE WILL COME AND STORE IN THE RAM UNTIL
SESSION END. BUT IF YOU WRITE PRAGMA SERIALLY_REUSABLE THEN THAT PACKAGE IS
ONE TIME CALL PACKAGE (MEANS IT WON’T STORE UNTIL SESSION END IMMEDIATELY
CLEAR FROM THE RAM)
EXAMPLE WITH PRAGMA SERIALLY_REUSABLE
CREATE OR REPLACE PACKAGE PKG_TEST_PRAGMA_SERIALLY AS
GN_NUMBER NUMBER := 1;
PRAGMA SERIALLY_REUSABLE;
END;
/

DECLARE
X NUMBER := 1;
BEGIN
PKG_TEST_PRAGMA_SERIALLY.GN_NUMBER := PKG_TEST_PRAGMA_SERIALLY.GN_NUMBER+1;
dbms_output.put_line( PKG_TEST_PRAGMA_SERIALLY.GN_NUMBER);

PKG_TEST_PRAGMA_SERIALLY.GN_NUMBER := PKG_TEST_PRAGMA_SERIALLY.GN_NUMBER+1;
dbms_output.put_line( PKG_TEST_PRAGMA_SERIALLY.GN_NUMBER);
END;

EXAMPLE2 WITHOUT PRAGMA SERIALLY_REUSABLE


CREATE OR REPLACE PACKAGE PKG_TEST_PRAGMA_SERIALLY AS
GN_NUMBER NUMBER := 1;
END;
/
41

DECLARE
X NUMBER := 1;
BEGIN
PKG_TEST_PRAGMA_SERIALLY.GN_NUMBER := PKG_TEST_PRAGMA_SERIALLY.GN_NUMBER+1;
dbms_output.put_line( PKG_TEST_PRAGMA_SERIALLY.GN_NUMBER);

PKG_TEST_PRAGMA_SERIALLY.GN_NUMBER := PKG_TEST_PRAGMA_SERIALLY.GN_NUMBER+1;
dbms_output.put_line( PKG_TEST_PRAGMA_SERIALLY.GN_NUMBER);
END;

/
EXTERNAL TABLE CREATION AND DIRECTORY CREATION

--CREATE DIRECTORY ON SYS SCHEMA


SELECT * FROM ALL_DIRECTORIES; --IF YOU RUN THIS QUERY YOU WILL GET PATH
WHERE YOU CAN CREATE DIRECTORY

SYNTAX:- CREATE DIRECTORY <DIRECTORY_NAME> AS <'PATH'>;


EXAMPLE:- CREATE DIRECTORY MY_DIR AS 'D:\APP\SYS-
1\PRODUCT\11.2.0\DBHOME_1\DEMO\SCHEMA\SALES_HISTORY\MY_DIR';
GRANT READ, WRITE ON DIRECTORY DIR_NAME TO SCHEMA_NAME

-- CREATE EXTERNAL TABLE ON YOUR SCHEMA


YOU HAVE TO CREATE CSV FILE BEFORE CREATE THE EXTERNAL TABLE , (OPEN XL SHEET
ENTER THE VALUES IN THE FIELDS AND SAVE AS CSV (MSDOS CSV))
--THEN ENTER DIRECTORY NAME AND CSV FILE NAME AT THE TIME OF EXTERNAL TABLE CREATION

CREATE TABLE EXT_TAB


(
A NUMBER,
B NUMBER
)
ORGANIZATION EXTERNAL
(
TYPE ORACLE_LOADER
DEFAULT DIRECTORY MY_DIR
ACCESS PARAMETERS
(
RECORDS DELIMITED BY 0X '0A'
SKIP 0
NOBADFILE NODISCARDFILE NOLOGFILE
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' RTRIM
MISSING FIELD VALUES ARE NULL
42

)
LOCATION (MY_DIR:'ABCD.CSV')
)
REJECT LIMIT UNLIMITED;

--BAD FILE , LOG FILE , DISCARD FILE


--BAD FILE CREATE:à WHEN THEY CANNOT BE LOADED BECAUSE OF ERRORS
--DISCARD FILE IS CREATED:-> WHEN THE FIRST RECORD TO BE DISCARDED (MEANS
WHEN “WHEN” CONDITION IS TRUE)
--LOG FILE IS CREATED:-> WHILE IT WAS ACCESSING DATA IN THE DATAFILE

BADFILE :-> CASE 1) CONDITION IS SATISFAIED BUT ORACLE LOADER NOT ABLE TO
INSERT THE DATA
INTO EXTERNAL_TABLE THEN BAD FILE WILL STORE THOSE RECORDS INFORMATION
CASE 2) IF THERE IS NO CONDITION FOR WHICH RECORDS ORACLE LOADER NOT
ABLE TO INSERT THE DATA
INTO EXTERNAL_TABLE, THEN BAD FILE WILL STORE THOSE RECORDS INFORMATION

DISCARD FILE :- IT WILL CREATE, WHEN WE ARE INSERTING DATA INTO EXTERNAL
TABLE BASED ON CONDITION,. FOR WHICH RECORDS CONDITION IS FAILED THOSE
RECORDS INFORMATION WILL BE STORED IN A DISCARD FILE

--BAD FILE , DISCARD FILE, LOG FILE CREATION


CREATE TABLE EXT_TAB
(
A NUMBER,
B NUMBER,c number,d number(5)
)
ORGANIZATION EXTERNAL
(
TYPE ORACLE_LOADER
DEFAULT DIRECTORY MY_DIR
ACCESS PARAMETERS
(
RECORDS DELIMITED BY 0X '0A'
SKIP 0
load when b = '345'
badfile MY_DIR:'dd.bad'
logfile MY_DIR:'LOGG.LOG'
discardfile MY_DIR:'ddd.disc'

FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' RTRIM


MISSING FIELD VALUES ARE NULL
)
LOCATION (MY_DIR:'DATA.CSV')
)
REJECT LIMIT UNLIMITED;

EX 2:-
--ONLY BAD FILE AND LOG FILE CREATION, WHEN WE ARE INSERTING DATA WITHOUT
-----ANY CONDITION
CREATE TABLE EXT_TAB
(
A NUMBER,
B NUMBER,
C DATE
43

)
ORGANIZATION EXTERNAL
(
TYPE ORACLE_LOADER
DEFAULT DIRECTORY MY_DIR
ACCESS PARAMETERS
(
RECORDS DELIMITED BY 0X '0A'
SKIP 0
BADFILE MY_DIR:'bad1.bad'
LOGFILE MY_DIR:'log1.log'
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' RTRIM
MISSING FIELD VALUES ARE NULL
(
A ,
B ,
C DATE ‘MM/DD/YY’
)
)
LOCATION (MY_DIR:'ABCD.CSV')
)
REJECT LIMIT UNLIMITED;
--ALTER EXTERNAL TABLE FILE NAME CHANGE
ALTER TABLE <EXTERNAL_TABLE> LOCATION <NEW_CSV_FILE.CSV);
ALTER TABLE EXT_TAB LOCATION (‘DEF.CSV’);
--ALTER EXTERNAL TABLE DIRECTORY NAME CHANGE
ALTER TABLE EXT_TAB DEFAULT DIRECTORY <NEW_DIRECTORY_NAME>
--ALTER EXTERNAL TABLE FIELDS TERMINATED BY
ALTER TABLE EXT_TAB ACCESS PARAMETERS (FIELDS TERMINATED BY '$')
JOBS CREATION
CREATE TABLE EMP_REPORT
(
COUNT_EMP NUMBER,
DEPTNO NUMBER,
SUM_SAL NUMBER(10,2),
REPORT_GEN_DATE DATE
);
--PROCEDURE
CREATE OR REPLACE PROCEDURE SP_EMP_REPORT AS
TYPE TYP_REC IS RECORD(COUNT_EMP NUMBER,DEPTNO NUMBER,SUM_SAL
NUMBER(10,2),REPORT_GEN_DATE DATE);
TYPE TYP_TAB IS TABLE OF TYP_REC INDEX BY BINARY_INTEGER;
TYP_EMP TYP_TAB;
BEGIN
DELETE FROM EMP_REPORT;
COMMIT;
SELECT COUNT(EMPNO),DEPTNO,SUM(SAL),SYSDATE BULK COLLECT INTO TYP_EMP FROM EMP
GROUP BY DEPTNO;
FORALL I IN 1..TYP_EMP.COUNT
INSERT INTO EMP_REPORT VALUES TYP_EMP(I);
COMMIT;
END;
IF YOU WANT EXECUTE ABOVE PROCEDURE DAILY OR MONTHLY OR YEARLY OR WKLY THEN YOU
HAVE TO CREATE JOB ON THIS PROCEDURE
DECLARE
X NUMBER;
44

BEGIN
DBMS_JOB.submit(X,
'BEGIN SP_EMP_REPORT; END;',
SYSDATE,
'SYSDATE + 1');
COMMIT;
END;
The Below Job Runs Everyday Early Morning At 3:00 Am
declare
x number;
y date :=trunc(sysdate+1);
begin
dbms_job.submit(x,'begin
sp_emp_report;end;',y+3/24,'sysdate+1');
commit;
end;
The Below Job Runs Next Year Same Date At 3:00am
declare
x number;
y date:=trunc(add_months(sysdate,12));
begin
dbms_job.submit(x,'begin
SP_EMP_REPORT;end;',y+3/24,'add_months(sysdate,12)');
commit;
end;
The Below Job Runs Every Day Morning At 3:45 Am
DECLARE
X NUMBER;
Y DATE :=TRUNC(SYSDATE+1);
BEGIN
DBMS_JOB.SUBMIT(X,'BEGIN SP_EMP_STATUS;
END;',Y+3/24+45/24/60,'SYSDATE+1');
COMMIT;
END;
--HOW TO DROP THE JOB
BEGIN
DBMS_JOB.remove(10); --HERE 10 IS JOB NUMBER,THIS YOU CAN FIND IN USER_JOBS TABLE (JOB
COLUMN)
END;
--HOW TO RUN THE JOB FORCEFULLY , ( IF YOU DID THIS THEN JOB SCHEDULE WILL CHANGE)
BEGIN
DBMS_JOB.run(169);
END;
--HOW TO BROKEN THE JOB
BEGIN
DBMS_JOB.broken(10,TRUE);--IF YOU WANT UN BROKEN THE JOB THEN GIVE 10,FALSE
--DBMS_JOB.broken(10,FALSE);
END;
45

ORACLE LOADER
TAKE THE FLAT FILE DATA IN CSV FORMAT AND KEEP THIS FILE IN SERVER OR LOCAL DRIVE
EX(10.1.46.220\ISECURITISATION\ISECURE_MIG_DATE\TEST_LOADER.CSV OR
C:\TEST_LOADER.CSV)

EX: FILE NAME: TEST_LOADER.CSV


DATA: 1437, 390,908
2) TAKE AN OTHER FILE WITH EXTENSION AS .CTL WHICH CONSISTS OF BELOW INFO
LOAD DATA
INFILE '\\10.1.46.220\SECURITISATION\ISECURE_MIG_DATA\TEST_LOADER.CSV'
INTO TABLE TEST123
FIELDS TERMINATED BY "," OPTIONALLY ENCLOSED BY '"'
( EMPNO, ENAME, DNAME )

CREATE TABLE TEST123 (EMPNO NUMBER (5), SAL NUMBER(5), DEPTNO NUMBER)
TRUNCATE TABLE TEST123

3) GO TO COMMAND PROMPT(DOS PROMPT) AND PAST THE COMMAND

SYNTAX: SQLLDR <SCHEMA_NAME>/<PASSWORD>@<DATABASENAME> CONTROL= FILE LOCATION

SQLLDR ISEC_PHASE2_TESTING/ISEC_PHASE2_TESTING@ORCL220NEW CONTROL= C:\TEST.CTL

4) IF THE ABOVE COMMAND PROMPT COMMAND IS EXECUTED PROPELY, DATA WILL BE INSERT
INTO TEST123 DATABASE TABLE FROM EXTERNAL FLAT FILE.

--QUERY THE TABLE


SELECT * FROM TEST123;

HOW TO STORE TABLE DATA INTO CSV FILE


DECLARE
FO UTL_FILE.FILE_TYPE;
BEGIN
FO := UTL_FILE.FOPEN('ISECURE_MIG_DATA',
'LIST_OF_OBJECT.CSV',
'W',
2000);
FOR I IN 1..5 LOOP
FOR J IN 1..3 LOOP
LV_STR := LV_STR ||','||J;
LV_STR := LTRIM(LV_STR);
UTL_FILE.PUTF(FO, '%S\N', LV_STR);
END LOOP;
LV_STR := NULL;
END LOOP;
UTL_FILE.FCLOSE;
END;
example:-
DECLARE
FO UTL_FILE.file_type;
LV_STR VARCHAR2(30) := '';
type tab_1 is table of emp%rowtype index by binary_integer;
typ_2 tab_1;
46

BEGIN --my_dir is a directory --insted of ddde.txt you can give any name --example data.csv,
xx.txt
FO := UTL_FILE.fopen('MY_DIR', 'ddde.txt', 'W', 2000);
--'w' to write new file in that directory , 2000--means no of charcters we can write upto in that file
select * bulk collect into typ_2 from emp;
for i in 1 .. typ_2.count loop
LV_STR := typ_2(i)
.empno || ',' || typ_2(i).ename || ',' || typ_2(i).sal
|| ',' || typ_2(i).job;
UTL_FILE.putf(FO, '%s\n', LV_STR);
LV_STR := ''; --\n --> means write in new line

end loop;

UTL_FILE.fclose(FO);
END;

DATABASE LINK CREATION


ONE USER OBJECT WANT TO SELECT ANOTHER USER , THEN SYNONYM IS REQUIRE.
(NOTE:- BOTH USERS SHOULD BE IN THE SAME DATABASE, THEN ONLY SYNONYM WILL WORK)

ONE DATABASE USER OBJECT WANT TO SELECT ANOTHER DATABASE USER , THEN DATABASE LINK IS
REQUIRE.
(NOTE:- BOTH USERS IN THE SAME DATABASE OR IN DIFFERENT DATABASES ALSO, DBLINK WILL WORK)

CREATE DATABASE LINK os90 connect to XXDMCCTF identified by XXDMCCTF using


'(DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = 10.1.46.226)
(PORT = 1521))
)
(CONNECT_DATA =
(SERVICE_NAME = test2)

TRIGGERS
1. TRIGGER IS A VALIDATION PROCESS WHICH OCCUR AUTOMATICALLY WITHOUT ANY EXPLICIT
COLUMN.
2. MAINLY WE USE TRIGGERS FOR MENTAIN AUDIT (HISTORY) AND WE USE FOR BUSINEES
REQUIREMENT
3. IMPLICITLY TRIGGER WILL BE FIRED, IF WE APPLY ANY DML OPERATION ON TABLE(DML
TRIGGER), IF YOU APPLY DDL ON SCHEMA.
DIFFERENCE BETWEEN BEFORE AND AFTER TRIGGER EVENTS
BEFORE AFTER
TRIGGER WILL BE FIRED BEFORE UPDATE OR TRIGGER WILL BE FIRED AFTER UPDATE OR
INSERT OR DELETE ON TABLE INSERT OR DELETE ON TABLE
IF TABLE HAVING UNIQUE CONSTRAINT AND IF TABLE HAVING UNIQUE CONSTRAINT AND
THAT TABLE HAVING BEFORE ROW LEVEL THAT TABLE HAVING AFTER ROW LEVEL
TRIGGER ,THEN IF YOU ARE TRYING TO INSERT TRIGGER ,THEN IF YOU ARE TRYING TO INSERT
47

DUPLICATE VALUES ON THAT TABLE FIRST DUPLICATE VALUES ON THAT TABLE.,FIRST


BEFORE ROW LEVEL TRIGGER WILL BE FIRED UNIQUE CONSTRAINT WILL BE FIRED
WE CAN CHANGE THE :NEW, :OLD VALUES IF WE TRY TO MODIFY :NEW, :OLD VALUES
EX: :NEW.EMPNO := 200, :OLD.SAL := 600 THEN THAT TRIGGER WILL CREATE WITH
COMPILATION ERRORS, MEANS WE CAN’T
MODIFY :NEW, :OLD VALUES IN AFTER ROW
LEVEL TRIGGER
DATA WON’T STORE IN BUFFER (MEANS: IT IS DATA FIRST WILL BE STORED IN BUFFER
NOT OCCUPY SPACE IN MEMORY . BECAUSE (MEANS: IT WILL OCCUPY SPACE IN MEMORY)
BEFORE INSERT TRIGGER WILL BE FIRE)

STATEMENT LEVEL TRIGGERS


CREATE OR REPLACE TRIGGER TRG_STATEMENT1
BEFORE INSERT OR UPDATE OR DELETE ON ACCOUNT_HOLDER_INFO
DECLARE
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
IF TRIM(TO_CHAR(SYSDATE, 'DAY')) IN ('SATURDAY', 'SUNDAY') THEN
INSERT INTO AUDIT_STATEMENT VALUES (1, USER, SYSDATE);
COMMIT;
RAISE_APPLICATION_ERROR(-20345,
' YOU CAN NOT MODIFY EMP TABLE ON SATURDAYS AND
SUNDAYS');
END IF;

END;

ROW LEVEL
MUTATING ERROR:-> MUTATING ERROR WILL OCCUR WHEN A ROW LEVEL TRIGGER TRY TO PERFORM
DML OPERATION OR SELECT STMT ON THE SAME TABLE , WHILE TRIGGER IS FIRING.

(EX : TRIGGER IS FIRING ON EMP TABLE BEFORE UPDATE CASE, INSIDE TRIGGER BODY SELECT STMT ON
SAME TABLE (EMP) THEN WE WILL GET MUTATING ERROR)

ON WHICH CASE MUTATING TRIGGER ERROR WILL OCCUR , IN ROW LEVEL TRIGGER?

ACTION TRIGGER IN ERROR STATUS TRIGGER IN ERROR STATUS


ON EVENT TRIGGE EVENT TRIGGER
TABLE (FIRE ON) R BODY (FIRE ON) BODY
INSERT BEFORE INSERT RECURSIVE AFTER INSERT INSERT ON MUTATING
ON EMP INSERT ON EMP ERROR X  ON EMP EMP ERROR X
ON EMP  
48

“ “ UPDATE NO ISSUE “ UPDATE MUTATING


ON EMP
 ON EMP ERROR X

“ “ DELETE NO ISSUE “ DELETE MUTATING
ON EMP  ON EMP ERROR X

“ “ SELECT NO ISSUE “ SELECT ON MUTATING
ON EMP  EMP ERROR X

UPDATE BEFORE INSERT MUTATING AFTER INSERT ON MUTATING
ON EMP UPDATE ON EMP ERROR X  UPDATE ON EMP ERROR X
ON EMP  EMP 
“ “ UPDATE MUTATING “ UPDATE MUTATING
ON EMP ERROR X  ON EMP ERROR X
 
“ “ DELETE MUTATING “ DELETE MUTATING
ON EMP ERROR X  ON EMP ERROR X
 
“ “ SELECT MUTATING “ SELECT ON MUTATING
ON EMP ERROR X  EMP ERROR X
 
DELETE BEFORE INSERT MUTATING AFTER DELETE INSERT ON MUTATING
ON EMP DELETE ON EMP ERROR X  ON EMP EMP ERROR X
ON EMP  
“ UPDATE MUTATING “ UPDATE MUTATING
ON EMP ERROR X ON EMP ERROR X
 
“ DELETE MUTATING “ DELETE MUTATING
ON EMP ERROR X ON EMP ERROR X
 
“ SELECT MUTATING “ SELECT ON MUTATING
ON EMP ERROR X EMP ERROR X
 

PRAGMA AUTONAMOUS_TRANSACTION ON TRIGGER TO RESOLVE MUTATING ERROR BUT STILL WE


GET SOME ERRORS

ACTION TRIGGER IN PRAGMA STATUS TRIGGER IN PRAGMA STATUS


ON EVENT TRIGGE AUTONAM EVENT TRIGGER AUTONAM
TABLE (FIRE ON) R BODY OUS (FIRE ON) BODY (ON OUS
(ON SAME
49

SAME ROWS)
ROWS)
INSERT BEFORE INSERT RECURSIVE AFTER INSERT INSERT ON RECURSIVE
ON EMP INSERT ON EMP ERROR X ON EMP EMP ERROR X
ON EMP  
“ “ UPDATE NO ISSUE “ UPDATE NO ISSUE
ON EMP
 ON EMP

“ “ DELETE NO ISSUE “ DELETE NO ISSUE
ON EMP  ON EMP 
“ “ SELECT NO ISSUE “ SELECT ON NO ISSUE
ON EMP  EMP 
UPDATE BEFORE INSERT NO ISSUE AFTER INSERT ON NO ISSUE
ON EMP UPDATE ON EMP
 UPDATE ON EMP

ON EMP EMP
“ “ UPDATE DEADLOCK “ UPDATE DEADLOCK
ON EMP X ON EMP X
 
“ “ DELETE NO ISSUE “ DELETE DEADLOCK
ON EMP
 ON EMP X
SAME 
ROWS
DELETE NO ISSUE DELETE
ON EMP
 ON EMP

(OTHER (OTHER NO ISSUE
ROWS) ROWS)
“ “ SELECT NO ISSUE “ SELECT ON NO ISSUE
ON EMP
 EMP

DELETE BEFORE INSERT NO ISSUE AFTER DELETE INSERT ON NO ISSUE
ON EMP DELETE ON EMP
 ON EMP EMP

ON EMP
“ UPDATE NOISSUE “ UPDATE DEADLOCK
ON EMP
 ON EMP X
“ “ UPDATE NOISSUE “ UPDATE NOISSUE
ON EMP
 ON EMP

(OTHER (OTHER
ROWS) ROWS)
“ DELETE NOISSUE
 ON EMP

(OTHER
ROWS)
“ DELETE DEADLOCK “ DELETE DEADLOCK
ON EMP X ON EMP X
 
“ SELECT NO ISSUE “ SELECT ON NO ISSUE
ON EMP
 EMP

WE CAN CHANGE :NEW, :OLD VALUES IN BEFORE ROWLEVEL TRIGGER


50

EX:
CREATE OR REPLACE TRIGGER BEFORE INSERT ON EMP
FOR EACH ROW
WHEN (:NEW.COMM < 500)
BEGIN
:NEW.COMM := 9000;
END;
/
EX :

CREATE OR REPLACE TRIGGER TRG_ROW_EMP


BEFORE INSERT OR DELETE OR UPDATE ON EMP
FOR EACH ROW
DECLARE
LN_COUNT NUMBER;
BEGIN
SELECT COUNT(*) INTO LN_COUNT FROM DEPT WHERE DEPTNO = :NEW.DEPTNO;
IF LN_COUNT = 0 THEN
INSERT INTO DEPT VALUES (:NEW.DEPTNO,'MANGER', 'HYDERABD');
END IF;
IF INSERTING THEN
INSERT INTO EMP_HISTORY VALUES (:NEW.EMPNO,NULL, :NEW.SAL, SYSDATE);
ELSIF UPDATING THEN
UPDATE EMP_HISTORY E
SET E.OLD_SAL = :OLD.SAL,
E.NEW_SAL = :NEW.SAL,
E.DATE_OF_CHANGES = SYSDATE
WHERE E.EMPNO = :OLD.EMPNO;
ELSIF DELETING THEN
INSERT INTO EMP_HISTORY VALUES (:OLD.EMPNO, :OLD.SAL, NULL, SYSDATE);
END IF;
END;

--HOW TO CREATE DDL TRIGGER (BEFORE )


CREATE OR REPLACE TRIGGER TRG_DDL1
BEFORE CREATE OR DROP OR ALTER ON SCHEMA
DECLARE
LN_1 VARCHAR2(50);
LN_2 VARCHAR2(50);
PRAGMA AUTONOMOUS_TRANSACTION;
LN_3 VARCHAR2(50);
LD_DATE DATE;
BEGIN
dbms_output.put_line('D');
INSERT INTO DDL_TRIGGER_INFO
select ORA_SYSEVENT, ora_dict_obj_type, ora_dict_obj_name, SYSDATE
-- INTO LN_1, LN_2, LN_3, LD_DATE
from DUAL;
COMMIT;
dbms_output.put_line(USER);
END;

/
--HOW TO CREATE COMPOUND TRIGGER
51

CREATE OR REPLACE TRIGGER TRG_ON_EMP


FOR INSERT ON EMP
COMPOUND TRIGGER
AFTER STATEMENT IS
BEGIN
IF TRIM(TO_CHAR(SYSDATE, 'DAY')) = 'TUESDAY' THEN
RAISE_APPLICATION_ERROR(-20679, 'YOU CAN NOT');
END IF;
DBMS_OUTPUT.PUT_LINE('AFTER STATEMENT LEVEL TRIGGER');
END AFTER STATEMENT;
BEFORE STATEMENT IS
BEGIN
DBMS_OUTPUT.PUT_LINE('BEFORE STATE MENT LEVEL');
END BEFORE STATEMENT;

BEFORE EACH ROW IS


BEGIN
DBMS_OUTPUT.PUT_LINE('BEFORE ROW LEVEL IS');
END BEFORE EACH ROW;
AFTER EACH ROW IS
BEGIN
DBMS_OUTPUT.PUT_LINE('AFTER ROW LEVEL TRIGGER');
END AFTER EACH ROW;

END;
/
--RETURNING CLAUSE
DECLARE
TYPE TYP_1 IS TABLE OF EMP.SAL%TYPE INDEX BY BINARY_INTEGER;

LN_SAL TYP_1;

---
LN_ENAME VARCHAR2(30);

BEGIN
UPDATE EMP
SET ENAME = ENAME || 'S'
WHERE EMPNO = 7369
RETURNING ENAME INTO LN_ENAME;

UPDATE EMP
SET SAL = SAL + 100
WHERE DEPTNO = 10
RETURNING SAL BULK COLLECT INTO LN_SAL;
--dbms_output.put_line( LN_SAL);
FOR I IN 1 .. LN_SAL.COUNT LOOP
dbms_output.put_line(LN_SAL(I));
END LOOP;

dbms_output.put_line(LN_ENAME);
END;
52

--DML TRIGGERS
create or replace trigger bt_pract.trg_after_row_emp
AFTER insert on emp
for each row
begin
DBMS_OUTPUT.PUT_LINE('AFTER ROW LEVEL trigger');
end;
/

create or replace trigger bt_pract.trg_after_stmt_emp after insert on emp


begin
DBMS_OUTPUT.PUT_LINE ('AFTER statement is');
end;
/

create or replace trigger bt_pract.trg_before_row_emp


before insert on emp
for each row
WHEN (NEW.EMPNO = 9009)
begin
DBMS_OUTPUT.PUT_LINE('before row level trigger');
:NEW.EMPNO := 8888;
end;
/

create or replace trigger bt_pract.trg_before_row_emp2


before insert on emp
for each row
begin
DBMS_OUTPUT.PUT_LINE('before row level trigger 2');
end;
/

CREATE OR REPLACE TRIGGER BT_PRACT.TRIGER_1 BEFORE INSERT OR UPDATE OR


DELETE ON EMP
BEGIN
IF INSERTING THEN
IF TRIM(TO_CHAR(SYSDATE,'DAY'))='MONDAY' THEN

RAISE_APPLICATION_ERROR(-20300, 'YOU CAN NOT DELETE TODAY');

END IF;
END IF;
END;
/

--IF REQUIRE THEN ONLY EXECUTE BELOW SCRIPT


53

CREATE OR REPLACE TRIGGER TRG_BEFORE_AUDIT_EMP


BEFORE UPDATE ON AUDIT_EMP
FOR EACH ROW

DECLARE
LN_COUNT NUMBER;
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN

--SELECT COUNT(*) INTO LN_COUNT FROM AUDIT_EMP;


UPDATE AUDIT_EMP SET SAL = 7777 WHERE EMPNO = 101;
/* insert into AUDIT_EMP
(EMPNO, ENAME, JOB, MGR, SAL, COMM, DEPTNO, HIREDATE, BONUS)
values
(103,
'JONES',
'ANALYST',
null,
19000,
2000,
10,
to_date('15-02-2016', 'dd-mm-yyyy'),
400);*/
/* DELETE FROM AUDIT_EMP;
DBMS_OUTPUT.PUT_LINE(10);*/

END;
/
CREATE OR REPLACE TRIGGER TRG_AFTER_AUDIT_EMP
AFTER INSERT ON AUDIT_EMP
FOR EACH ROW

DECLARE
LN_COUNT NUMBER;
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN

--SELECT COUNT(*) INTO LN_COUNT FROM AUDIT_EMP;


-- UPDATE AUDIT_EMP SET SAL = 7777 WHERE EMPNO = 102;
/*INSERT INTO AUDIT_EMP
(EMPNO, ENAME, JOB, MGR, SAL, COMM, DEPTNO, HIREDATE, BONUS)
values
(103,
'JONES',
'ANALYST',
null,
19000,
2000,
10,
to_date('15-02-2016', 'dd-mm-yyyy'),
400);*/
DELETE FROM AUDIT_EMP;
DBMS_OUTPUT.PUT_LINE(10);
54

END;
/

BFILE----
-----------
CREATE TABLE NEW_BFILE (X NUMBER, Y BFILE);
CREATE TABLE NEW_BFILE (X NUMBER, Y BFILE);
INSERT INTO NEW_BFILE VALUES (20, BFILENAME('MY_DIR','FLOW.JPG'));

BLOB---
----------
CREATE TABLE TAB_BLOB
(
X NUMBER,
Y BLOB
);
DECLARE
SRC_LOB BFILE:= BFILENAME('MY_DIR', 'FLOW.JPG');
DEST_LOB BLOB;

BEGIN
INSERT INTO TAB_BLOB
(X,Y)
VALUES
(101,
EMPTY_BLOB())
RETURNING Y INTO DEST_LOB;

DBMS_LOB.OPEN(SRC_LOB, DBMS_LOB.LOB_READONLY);
DBMS_LOB.LOADFROMFILE( DEST_LOB,
SRC_LOB,
DBMS_LOB.GETLENGTH(SRC_LOB));
DBMS_LOB.CLOSE(SRC_LOB);
END;
/

--VARRAY INSIDE THE TABLE


CREATE OR REPLACE TYPE TYP_V IS VARRAY(10) OF NUMBER;
CREATE TABLE TEST_3(X NUMBER, Y NUMBER, Z TYP_V);
INSERT INTO TEST_3 VALUES (10,20, TYP_V(10,20,30));

--NESTED TABLE
select * from TEST_3;
CREATE TYPE TYP_O IS OBJECT (A NUMBER, B NUMBER);
CREATE TYPE TYP_T IS TABLE OF TYP_O;
CREATE TABLE TYPP (X NUMBER, Y TYP_O);
INSERT INTO TYPP VALUES (2, TYP_O(20,34));

---OBJECTS
CREATE OR REPLACE TYPE TYP_OBJ IS OBJECT (PRO_NAME VARCHAR2(20), PRO_MODEL
VARCHAR2(20), PRO_COUNT NUMBER);

CREATE OR REPLACE TYPE TYP_TAB IS TABLE OF TYP_OBJ;

CREATE OR REPLACE TYPE TYP_VARRAY IS VARRAY(6) OF VARCHAR2(20)


55

CREATE TABLE PRODUCT_DET(PRODUCT_TYPE VARCHAR2(20), PRODUCT_INFO TYP_VARRAY);

INSERT INTO PRODUCT_DET VALUES ('SAMSUNG',


TYP_VARRAY('MOBILES','TABS','LAPTOP','COMPUTER', 'TV','REF'))

CREATE TABLE PRODUCT_INFO (PRODUCT_TYPE VARCHAR2(20), PRODUCT_INFO TYP_OBJ);

INSERT INTO PRODUCT_INFO VALUES ('LG', TYP_OBJ('REFG','150L',300));

SELECT * FROM PRODUCT_INFO;

HOW TO USE OBJECT IN A PROCEDURE OR FUNCTION OR ANANOMOUS BLOCK


----------------------------------------------------------------
CREATE OR REPLACE TYPE TYP_EMP IS OBJECT (EMPID NUMBER, ENAME VARCHAR2(30), SAL
NUMBER);
CREATE OR REPLACE TYPE TYP_NEST IS TABLE OF TYP_EMP;

CREATE OR REPLACE PROCEDURE SP_OBJECTGS (X IN TYP_NEST)


AS
BEGIN
FOR I IN 1..X.COUNT LOOP

DBMS_OUTPUT.PUT_LINE (X(I).EMPID);
END LOOP;
END SP_OBJECTGS ;
/
CREATE OR REPLACE PROCEDURE SP_TEST_OBJECTS
AS
TYP TYP_NEST;
BEGIN

SELECT TYP_EMP( EMPNO, ENAME, SAL) BULK COLLECT INTO TYP FROM EMP;
SP_OBJECTGS(TYP);
END SP_TEST_OBJECTS;
/

CREATE OR REPLACE TYPE TYP_OBJIC IS OBJECT(EMPID NUMBER,ENAME


VARCHAR2(80))
CREATE OR REPLACE TYPE TYP_N IS TABLE OF TYP_OBJIC
DECLARE
TYP_EMP typ_N;
BEGIN
SELECT TYP_OBJIC(EMPNO,ENAME) BULK COLLECT INTO TYP_EMP FROM
EMP;
FOR I IN 1..TYP_EMP.COUNT LOOP
DBMS_OUTPUT.PUT_LINE (TYP_EMP(i).EMPID||TYP_EMP(I).ENAME);
END LOOP;
END;

CREATE OR REPLACE TYPE TYP_V IS VARRAY(3) OF VARCHAR2(40)


56

CREATE TABLE ITEM_DET(IT_NO NUMBER,IT_INFO TYP_V);


INSERT INTO ITEM_DET VALUES(1,TYP_V('REF','500','5LTR'))
SELECT * FROM ITEM_DET;
NESTED TABLE
CREATE TYPE TYP_NEW_OBJ AS OBJECT(X VARCHAR2(30), Y VARCHAR2(30), Z VARCHAR2(30));
CREATE TYPE TYP_NEW IS TABLE OF TYP_NEW_OBJ;
CREATE TABLE FLIGHT_INFO (FLIGHT_NAME VARCHAR2(30), FLIGHT_NO TYP_NEW) NESTED TABLE
FLIGHT_NO STORE AS NEW_TAB;

--CREATE TABLE FLIGHT_DETAILS (FLIGHT_NAME VARCHAR2(30), FLIGHT_NO TYP_NEW_OBJ);

INSERT INTO FLIGHT_INFO VALUES ( 'JET AIRWAYS', TYP_NEW ( TYP_NEW_OBJ ('SP-401-MUM-VIZ','SP-402-VIZ-


MUM','SP-403-MUM-VIZ'),
TYP_NEW_OBJ ('SP-601-MUM-HYD','SP-602-HYD-MUM','SP-501-HYD-MUM'),
TYP_NEW_OBJ ('SP-401-MUM-VIZ','SP-402-VIZ-MUM','SP-403-MUM-VIZ'),
TYP_NEW_OBJ ('SP-601-MUM-HYD','SP-602-HYD-MUM','SP-501-HYD-MUM')));

SELECT * FROM TABS


SELECT * FROM FLIGHT_INFO
--HOW TO CREATGE TABLE SPACES
CREATE TABLESPACE RAJA_PRACT_TAB DATAFILE
'C:\ORACLEXE\ORADATA\XE\RAJA_PRACT_TAB.DBF' SIZE 500M AUTOEXTEND ON MAXSIZE
1024M;
ALTER TABLESPACE RAJA_PRACT_TAB ADD DATAFILE
'C:\ORACLEXE\ORADATA\XE\RAJA_PRACT_TAB2.DBF' SIZE 500M AUTOEXTEND ON MAXSIZE
1024M;
--TABLESPACE PERMISSION TO USER
ALTER USER <SCHEMA_NAME> QUOTA UNLIMITED ON RAJA_PRACT_TAB
--DROP TABLE SPACE
DROP TABLESPACE <TABLE_SPACE_NAME>;
--DROP TABLESPACE ALONG WITH DATAFILE
DROP TABLESPACE <TABSPACE_NAME> INCLUDING CONTENTS AND DATAFILES;
--DROP TABLESPACE ALONG WITH CONSTRAINTS
DROP TABLESPACE <TABSPACE_NAME> INCLUDING CONTENTS CASCADE CONSTRAINTS;
--DIRECTORY PERMISSION TO USER (SCHEMA)
GRANT READ, WRITE ON DIRECTORY <DIR_NAME> TO <USER_NAME>;
--ROLE CREATION
CREATE ROLE <ROLE_NAME>;
GRANT CONNECT, RESOURCE, ALTER SESSION, DEBUG CONNECT SESSION, CREATE
SESSION, CREATE TABLE, CREATE VIEW, CREATE SYNONYM,EXECUTE PROCEDURE,
CREATE PROCEDURE TO <ROLE_NAME>
GRANT <ROLE_NAME> TO <USER_NAME>
--PERMISSION TO SCHEMA
GRANT CONNECT, RESOURCE, ALTER SESSION, DEBUG CONNECT SESSION, CREATE
SESSION, CREATE TABLE, CREATE VIEW, CREATE SYNONYM,EXECUTE PROCEDURE,
CREATE PROCEDURE TO <SCHEMA_NAME>
--INSTEAD OF TRIGGER
CREATE VIEW VW_EDEPT AS SELECT E.*,D.DNAME,D.LOC FROM EMP E, DEPT D
WHERE E.DEPTNO = D.DEPTNO
--WE CAN NOT BELOW STATEMENT
INSERT INTO VW_EDEPT VALUES (20,'XX',50,'HR','HYD');
--CREATE INSTEAD OF TRIGGER
CREATE OR REPLACE TRIGGER TRG_INSTED
INSTEAD OF INSERT OR UPDATE OR DELETE ON VW_EDEPT
FOR EACH ROW
BEGIN
57

INSERT INTO DEPT VALUES (:NEW.DEPTNO, :NEW.DNAME, :NEW.LOC);


INSERT INTO EMP VALUES (:NEW.EMPNO, :NEW.ENAME, :NEW.DEPTNO);

END;
--NOW WE CAN APPLY DML
INSERT INTO VW_EDEPT VALUES (20,'XX',50,'HR','HYD');

CLUSTERS
 IT HOLDS THE COMMON COLUMN SHARED BY TWO TABLES
 IT WILL IMPROVE PERFORMANCE WHILE RETIEVING OR MANIPULATING DATA FROM MASTER-
CHILD TABLES
 IT HAS TO BE CREATED BEFORE CREATING TABLES.
CREATE CLUSTER C1(DEPTNO NUMBER(5));
CREATE TABLE DEPT (DEPTNO NUMBER(5), DNAME VARCHAR2(30), LOC VARCHAR2(30))
CLUSTER C1(DEPTNO);
CREATE TABLE EMP (EMPNO NUMBER, ENAME VARCHAR2(30) , DEPTNO NUMBER(5))
CLUSTER C1(DEPTNO);
CREATE INDEX IDX_C1 ON CLUSTER C1;

--to find error line number

Create or replace procedure ap_error_stack as


x number(2);
begin
for i in 1 .. 10 loop
if i = 1 then
dbms_output.put_line('yes');
else
dbms_output.put_line('no');
end if;
end loop;
x := 100;
exception
when others then
dbms_output.put_line(dbms_utility.format_error_backtrace);
dbms_output.put_line(dbms_utility.format_error_stack);
end;
/

---how to use dbms_profiler


create or replace procedure ap_error_stack as
x number(2);
begin
for i in 1 .. 10 loop
if i = 1 then
dbms_output.put_line('yes');
else
dbms_output.put_line('no');
end if;
58

end loop;
x := 100;
exception
when others then
dbms_output.put_line(dbms_utility.format_error_backtrace);
dbms_output.put_line(dbms_utility.format_error_stack);
end;
/
proftab.sql--dbms_profiler tables --plsql_profiler_data, plsql_profiler_units, all_source
dbmspbp.sql--dbms_profiler spec/body

exec dbms_profiler.start_profiler('SP_DBMS_PROFILER');
exec SP_DBMS_PROFILER;
exec dbms_profiler.stop_profiler;

select u.unit_owner,
u.unit_name,
u.unit_type,
d.line#,
d.total_occur,
s.TEXT,
d.total_time / 1000000 total_time
from all_source s, plsql_profiler_units u, plsql_profiler_data d
where u.runid = d.runid
and u.unit_number = d.unit_number
and s.owner = u.unit_owner(+)
and s.name = u.unit_name(+)
and s.type = u.unit_type(+)
and s.line = d.line#(+)
and s.name = upper('SP_DBMS_PROFILER')
--and s.owner = upper('&&owner')
order by s.line

PARTITION AND TYPES OF PARTITION

PARTITION ALLOWS A TABLE OR INDEX TO BE SUBDIVIDED INTO SMALLER PIECES, WHERE EACH PIECE
OF SUCH A DATABASE OBJECT CALLED A PARTITION. EACH PARTITION HAS ITS OWN NAME.
WHEN PARTITION A TABLE:-
TABLE IS GRATER THAN 2GB
WHEN THE CONTENTS OF A TABLE TO BE DISTRIBUTED ACROSS DIFFERENT TYPES OF STORAGE DEVICES.
--list partiotion example
CREATE TABLE employees
(
id NUMBER(10),
first_name VARCHAR2(20),
last_name VARCHAR2(20),
country VARCHAR2(30)
)
59

PARTITION BY LIST (country)


(
PARTITION europe VALUES ('ENGLAND', 'FRANCE', 'ITALY', 'SWITZERLAND') tablespace tab_1,
PARTITION america VALUES ('AMERICA') tablespace tab_2,
PARTITION unknown VALUES (NULL) tablespace tab_3
);
--range partition
CREATE TABLE INVOICES_RANGE
(
INVOICE_NO NUMBER NOT NULL,
INVOICE_DATE DATE NOT NULL,
COMMENTS VARCHAR2(500)
)
PARTITION BY RANGE (INVOICE_DATE)
(
PARTITION INVOICE_Q1 VALUES LESS THAN (TO_DATE('01/05/2010','DD/MM/YYYY')) TABLESPACE
INV_2010,
PARTITION INVOICE_Q2 VALUES LESS THAN (TO_DATE('01/09/2010','DD/MM/YYYY')) TABLESPACE
INV_2010,
PARTITION INVOICE_Q3 VALUES LESS THAN (TO_DATE('01/01/2011','DD/MM/YYYY')) TABLESPACE
INV_2010,
PARTITION INVOICE_Q4 VALUES LESS THAN (TO_DATE('01/05/2011','DD/MM/YYYY')) TABLESPACE
INV_2011,
PARTITION INVOICE_Q5 VALUES LESS THAN (TO_DATE('01/09/2011','DD/MM/YYYY')) TABLESPACE
INV_2011,
PARTITION INVOICE_Q6 VALUES LESS THAN (TO_DATE('01/01/2012','DD/MM/YYYY')) TABLESPACE
INV_2011,
PARTITION INVOICE_Q7 VALUES LESS THAN (TO_DATE('01/05/2012','DD/MM/YYYY')) TABLESPACE
INV_2012,
PARTITION INVOICE_Q8 VALUES LESS THAN (TO_DATE('01/09/2012','DD/MM/YYYY')) TABLESPACE
INV_2012,
PARTITION INVOICE_Q9 VALUES LESS THAN (TO_DATE('01/01/2013','DD/MM/YYYY')) TABLESPACE
INV_2012
);

--hash partition
CREATE TABLE INVOICES_Hash
(
INVOICE_NO NUMBER NOT NULL,
INVOICE_DATE DATE NOT NULL,
COMMENTS VARCHAR2(500)
)
PARTITION BY HASH (INVOICE_NO)
PARTITIONS 4
STORE IN (INV_1,INV_2,INV_3,INV_4);
---how to find table space name and free space in that tablespace
select df.tablespace_name "Tablespace",
60

totalusedspace "Used MB",


(df.totalspace - tu.totalusedspace) "Free MB",
df.totalspace "Total MB",
round(100 * ( (df.totalspace - tu.totalusedspace)/ df.totalspace))
"Pct. Free"
from
(select tablespace_name,
round(sum(bytes) / 1048576) TotalSpace
from dba_data_files
group by tablespace_name) df,
(select round(sum(bytes)/(1024*1024)) totalusedspace, tablespace_name
from dba_segments
group by tablespace_name) tu
where df.tablespace_name = tu.tablespace_name ;

WHERE CURRENT OF STATEMENT


IF YOU PLAN ON UPDATING OR DELETING RECORDS THAT HAVE BEEN REFERENCED BY A SELECT FOR
UPDATE STATEMENT, WE CAN USE WHERE CURRENT OF STATEMENT

(WHERE CURRENT OF STATEMENT ALLOWS YOU TO UPDATE OR DELETE THE RECORD THAT WAS LAST
FETCHED BY THE CURSOR)

EXAMPLE
DECLARE
CURSOR C1 AS SELECT COURSE FROM COURSE_TAB WHERE COURSE_NAME = ‘ORACLE’ FOR UPDATE
OF COURSE_NAME;
BEGIN
UPDATE COURSE_TAB SET COURSE_NAME = ‘ORACLE’ WHERE CURRENT OF C1;
COMMIT;
END;
/
--OPTIMIZER
A long time ago, the only optimizer in the Oracle database was the Rule-Based Optimizer (RBO).
Basically, the RBO used a set of rules to determine how to execute a query.
If an index was available on a table, the RBO rules said to always use the index.
There are some cases where the use of an index slowed down a query.
--cost based optimization
The Oracle cost-based optimizer is designed to determine the most efficient way to carry out a SQL
statement
-- optimization
choosing the most efficient way of executing a SQL statement
--hint is
if you write hint in sql statements then it suggets to optimizer to how to
statement should be execute.
( by using hints you will be able to choose the execution plans.)
--examples
SELECT /*+ INDEX (employees emp_department_ix)*/
employee_id, department_id
61

FROM employees
WHERE department_id > 50;

SELECT /*+ INDEX_COMBINE(e emp_manager_ix emp_department_ix) */ *


FROM employees e
WHERE manager_id = 108
OR department_id = 110;

SELECT /*+ NO_INDEX(employees emp_empid) */ employee_id


FROM employees
WHERE employee_id > 200;
--The FULL hint explicitly chooses a full table scan for the specified table
SELECT /*+ FULL(e) */ employee_id, last_name
FROM employees e
WHERE last_name LIKE :b1;
--ordered hint
The ORDERED hint causes Oracle to join tables
in the order in which they appear in the FROM clause.
SELECT /*+ORDERED */ o.order_id, c.customer_id, l.unit_price * l.quantity
FROM customers c, order_items l, orders o
WHERE c.cust_last_name = :b1
AND o.customer_id = c.customer_id
AND o.order_id = l.order_id;

--pipeline function
create function
gen_numbers(n in number default null)
return array
PIPELINED
as
begin
for i in 1 .. nvl(n,999999999)
loop
pipe row(i);
end loop;
return;
end;
/

Function created.

Suppose we needed three rows for something. We can now do that in one of two ways:

select * from TABLE(gen_numbers(3));

COLUMN_VALUE
------------
1
62

2
3

or

select * from TABLE(gen_numbers)


where rownum <= 3;

COLUMN_VALUE
------------
1
2
3

Now we are ready to re-answer the original question, using the following functionality:

select *
from (
select *
from (select * from table(gen_numbers(49)))
order by dbms_random.random
)
where rownum <= 6
/

COLUMN_VALUE
------------
47
42
40
15
48
23
--by using pivot command we can convert column data into column headings
select *
from (select ename, job from emp) PIVOT(count(JOB) for job in
('SALESMAN','ANALYST','CLERK')) order by ename
--wm_concat--it is working like listagg
select deptno,wm_concat(ename) from emp group by deptno .

--INDEX SCAN TYPES


1)Index Unique Scans
2)Index Range Scans
3)Index Range Scans Descending
4)Index Skip Scans
5)Full Scans
6)Fast Full Index Scans
--JOIN TYPES
63

HASH JOIN
NESTED LOOP JOIN
SORT MERGE JOIN

You might also like