PLSQL NOTES
PLSQL NOTES
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
VARIABLE DECLARATION:
1) ALL SQL DATA TYPE ARE SUPPORTED
EXAMPLE:
DECLARE
LN_EMPNO NUMBER(4);
LV_ENAME VARCHAR2(25);
LD_DOJ DATE;
BEGIN
2
DBMS_OUTPUT.PUT_LINE(‘HI’);
END;
EXECUTABLE STATEMENTS
ATRIBUTE DECLARATION:
SUPPORTS TO DEFINE THE VARIABLES EYNAMICALLY ACCORDING TO TABLE
STRUCTURE.
3
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 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;
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;
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
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
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);
--2ND EXAMPLE
DECLARE
LN_COUNT NUMBER(10);
LN_EMPNO NUMBER(10);
LN_SAL VARCHAR2(30);
BEGIN
6
--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
---%ISOPEN
IF CUR_EMP_DAT%ISOPEN THEN
CLOSE CUR_EMP_DATA;
END IF;
END;
8
FETCH CUR_EMP
INTO VC_EMP;
EXIT WHEN(CUR_EMP%NOTFOUND);
END LOOP;
CLOSE CUR_EMP;
END;
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);
DECLARE
9
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
END LOOP;
COMMIT;
END;
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
VC_EMP EMP%ROWTYPE;
VC_DEPT DEPT%ROWTYPE;
BEGIN
dbms_output.put_line('');
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?
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;
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
PROCEDURE EXAMPLES
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:
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
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
END;
WE CAN WRITE ANY NO OF BEGIN AND ENDS INSIDE BEGEN AND END
END LOOP;
COMMIT;
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
END;
VEC EMP%ROWTYPE;
LN_BONUS NUMBER(10,2);
EX EXCEPTION ;
BEGIN
OPEN EC;
LOOP
FETCH EC INTO VEC ;
EXIT WHEN EC%NOTFOUND;
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;
ELSE
UPDATE EMP E SET E.BONUS = LN_BONUS WHERE
EMPNO = VEC.EMPNO;
END IF;
22
END LOOP;
COMMIT;
END;
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
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
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
END LOOP;
COMMIT;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(SQLERRM);
ROLLBACK;
END;
/
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
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;
BEGIN
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;
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
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
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
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
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;
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
BEGIN
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;
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
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);
--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
DECLARE
TYPE TYP_VARRAY IS VARRAY(3) OF NUMBER;
TYP_VAR TYP_VARRAY := TYP_VARRAY(100, 200, 300);
--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);
--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(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);
--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(TYP_NEST.NEXT(2));
DBMS_OUTPUT.PUT_LINE(TYP_NEST.NEXT(3));
END;
--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;
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;
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;
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;
END;
PACKAGE_BODY:
CREATE OR REPLACE PACKAGE BODY PKG_TEST AS
BEGIN
SP_SUM_OF_NUMBERS(P1, P2, P_SUM);
SP_SMULT_OF_NUMBERS(P1, P2, P_MUL);
P_OUT_TODAY := G_DATE;
END;
END;
-- PACKAGE SPEC:
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;
/
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;
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
)
LOCATION (MY_DIR:'ABCD.CSV')
)
REJECT LIMIT UNLIMITED;
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
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)
CREATE TABLE TEST123 (EMPNO NUMBER (5), SAL NUMBER(5), DEPTNO NUMBER)
TRUNCATE TABLE TEST123
4) IF THE ABOVE COMMAND PROMPT COMMAND IS EXECUTED PROPELY, DATA WILL BE INSERT
INTO TEST123 DATABASE TABLE FROM EXTERNAL FLAT FILE.
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;
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)
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
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?
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
EX:
CREATE OR REPLACE TRIGGER BEFORE INSERT ON EMP
FOR EACH ROW
WHEN (:NEW.COMM < 500)
BEGIN
:NEW.COMM := 9000;
END;
/
EX :
/
--HOW TO CREATE COMPOUND TRIGGER
51
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;
/
END IF;
END IF;
END;
/
DECLARE
LN_COUNT NUMBER;
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
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
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;
/
--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);
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;
/
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;
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 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
--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
(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;
--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:
COLUMN_VALUE
------------
1
62
2
3
or
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 .
HASH JOIN
NESTED LOOP JOIN
SORT MERGE JOIN