Sie sind auf Seite 1von 53

PL/SQL

--> PROCEDURAL LANGUAGE/STANDARD QUERY LANGUAGE

--> SIGNIFICATNT MEMBER OF ORACLE PROHRAMMING TOOL SET

--> USED TO CODE SERVER SIDE PROGRAMMING

--> CASE INSENSITIVE PROGRAMMING LANGUAGE

--> BLOCKS ARE BASIC PROGRAMMING UNITS IN PL/SQL

--> TYPES OF BLOCKS: 1. ANONYMOUS BLOCKS

2. NAMED BLOCKS

ANONYMOUS BLOCK
NAMED BLOCK
|
|

----------------------------------------------------
| |
|
| |
|
DECLARATION SECTION |
EXCEPTION HANDLING SECTION
|
EXECUTION
SECTION

--> PROTOTYPE OF ANONYMOUS BLOCK --> DECLARE


---- DECLARATION STATEMENTS

BEGIN
---- EXECUTABLE
STATEMENTS

EXCEPTIONS
---- EXCEPTION
HANDLING STATEMENTS
END;

SQL> SET SERVEROUTPUT ON;

DECLARE

MYVAR VARCHAR2(12):= 'KARTHIK';

BEGIN

DBMS_OUTPUT.PUT_LINE(MYVAR);

END;

SQL> DECLARE
MYVAR1 VARCHAR2(20);

BEGIN

MYVAR1:='KARTHIK KONANKI';

DBMS_OUTPUT.PUT_LINE(MYVAR1);

END;

SQL> DECLARE
V_NAME VARCHAR2(15);

BEGIN
V_NAME := 'KARTHIK';
DBMS_OUTPUT.PUT_LINE(V_NAME);
END;

SELECT * FROM EMP;

SQL> DECLARE
V_SALARY NUMBER(8);

BEGIN
SELECT SAL INTO V_SALARY FROM EMP
WHERE EMPNO=7654;
DBMS_OUTPUT.PUT_LINE(V_SALARY);
END;
/

SQL> DECLARE
V_SALARY NUMBER(8);
V_NAME VARCHAR2(15);
BEGIN
SELECT SAL, ENAME INTO V_SALARY,
V_NAME FROM EMP
WHERE EMPNO=7654;
DBMS_OUTPUT.PUT_LINE(V_SALARY ||' IS
THE SALARY OF '||V_NAME);
END;
/

ANCHORED DATA TYPES:

--> DATA TYPE WHICH YOU ASSIGN TO A VARIABLE


BASED ON A DATABASE OBJECT

SYNTAX: VARIABLE_NAME TYPE-ATTRIBUTE %TYPE

SQL> DECLARE

V_NAME EMP.ENAME%TYPE

BEGIN

SELECT ENAME INTO V_NAME FROM EMP WHERE


EMPNO=7654;
DBMS_OUTPUT.PUT_LINE(V_NAME);

END;
/

SQL> DECLARE
VNAME VARCHAR2(15);
BEGIN
SELECT ENAME INTO VNAME FROM EMP WHERE
EMPNO=7654;
DBMS_OUTPUT.PUT_LINE(VNAME);
END;
/

CONSTANTS IN PL/SQL:

--> CONSTANT IS A USER DEFINED


IDENTIFIER WHOSE VALUE REMAINS UNCHANGED THROUGHOUT THE PROGRAM

SYNTAX: CONSTANT_NAME
CONSTANT DATATYPE(DW):= VALUE;

SQL> SET SERVEROUTPUT ON;

SQL> DECLARE
V_PI CONSTANT NUMBER(7,6):=3.141592;
BEGIN
DBMS_OUTPUT.PUT_LINE(V_PI);
END;

SQL> DECLARE
V_PI CONSTANT NUMBER(7,6);
BEGIN
V_PI:= 3.141592
DBMS_OUTPUT.PUT_LINE(V_PI_1);
END;
--> ERROR

--> USING DEFAULT KEYWORD

SQL> DECLARE
V_PI CONSTANT NUMBER(7,6) DEFAULT
3.141592;
BEGIN
DBMS_OUTPUT.PUT_LINE(V_PI);
END;

--> USING NOT NULL KEYWORD

SQL> DECLARE
V_PI CONSTANT NUMBER(7,6) NOT NULL
DEFAULT 3.141592;
BEGIN
DBMS_OUTPUT.PUT_LINE(V_PI);
END;
BIND VARIABLES | HOST VARIABLES:

--> BIND VARIABLES IN ORACEL


DATABASE CAN BE DEFINED AS THE VARIABLES THAT WE CREATE IN SQL PLUS AND THEN
REFERENCE IN PL/SQL

SQL> VARIABLE V_BIND


VARCHAR2(10);

SQL> EXEC :V_BIND :=


'KARTHIK';

SQL> BEGIN
:V_BIND := 'KARTHIK';
END;
/

--> USING DBMS_OUTPUT

SQL> BEGIN
:V_BIND := 'KARTHIK';

DBMS_OUTPUT.PUT_LINE(:V_BIND);
END;
/

--> PRINT COMMAND

SQL> PRINT :V_BIND;

--> AUTO PRINT

SQL> SET AUTOPRINT ON;

CONTROL STATEMENTS:

--> STATEMENTS WHICH ALLOW YOU TO CONTROL THE


EXECUTION FLOW OF THE PROGRAM DEPENDING ON A CONDITION

--> STATEMENTS IN THE PROGRAM ARE NOT


NECESSARILY EXECUTED IN A SEQUENCE RATHER ONE OR OTHER GROUP OF STATEMENTS ARE
EXECUTED DEPENDING ON THE EVALUATION OF A CONDITION

--> TWO TYPES: 1. IF STATMENT: IF THEN

IF THEN ELSE

IF THEN ELSEIF

2. CASE
STATMENT: SIMPLE CASE

SEARCHED CASE

IF-THEN STATEMENT:

SYNTAX: IF CONDITION THEN


STATMENT 1;
...
...
STATMENT N;
END IF;

SQL> SET SERVEROUTPUT ON;

SQL> DECLARE
V_NUM NUMBER :=9;
BEGIN
IF V_NUM < 10 THEN
DBMS_OUTPUT.PUT_LINE('INDISE THE
IF');
END IF;
DBMS_OUTPUT.PUT_LINE('OUTSIDE THE
IF');
END;
/

SQL> DECLARE
V_WEB VARCHAR2(30) :=
'KARTHIK_KONANKI.COM';
V_AUTHOR VARCHAR(20) := 'KARTHIK
KONANKI';
BEGIN
IF V_WEB = 'KARTHIK_KONANKI.COM' AND
V_AUTHOR = 'KONANKI KARTHIK' THEN
DBMS_OUTPUT.PUT_LINE('EVERYTHING IS
AWESOME');
END IF;
DBMS_OUTPUT.PUT_LINE('GIVE THIS
VIDEO THUMBS UP');
END;
/

IF THEN ELSE STATEMENT:

SYNTAX: IF CONDITION THEN


STATEMENT 1;
ELSE
STATEMENT 2;
END IF;
STATEMENT 3;

SQL> SET SERVEROUTPUT ON;

SQL> DECLARE
V_NUM NUMBER :=
&ENTER_A_NUMBER;
BEGIN
IF MOD(V_NUM, 2)=0
THEN

DBMS_OUTPUT.PUT_LINE(V_NUM ||' IS EVEN');


ELSE
DBMS_OUTPUT.PUT_LINE(V_NUM ||' IS ODD');
END IF;

DBMS_OUTPUT.PUT_LINE('IF THEN ELSE CONSTRUCT IS COMPLETE');


END;
/

IF THEN ELSEIF STATEMENT:

SYNTAX: IF CONDITION_1 THEN


STATEMENT 1;
ELSIF CONDITION_2
THEN
STATEMENT 2;
ELSIF CONDITION_3
THEN
STATEMENT 3;
....
....
ELSE CONDITION_N;
STATEMENT N;
ENDIF;

SQL> SET SERVEROUTPUT ON;

SQL> DECLARE
V_PLACE
VARCHAR2(30):='&ENTER_PLACE';
BEGIN
IF V_PLACE =
'METROPOLIS' THEN

DBMS_OUTPUT.PUT_LINE('CITY IS PROTECTED BY SUPERMAN');


ELSIF V_PLACE =
'GOTHAM' THEN

DBMS_OUTPUT.PUT_LINE('CITY IS PROTECTED BY BATMAN');


ELSIF V_PLACE =
'AMAZON' THEN

DBMS_OUTPUT.PUT_LINE('CITY IS PROTECTED BY WONDER-WOMEN');


ELSE

DBMS_OUTPUT.PUT_LINE('PLEASE CALL AVENGERS');


END IF;

DBMS_OUTPUT.PUT_LINE('THANKS FOR CONTACTING US');


END;
/

LOOPS IN PL\SQL STATEMENTS:

--> LOOPS EXECUTES BLOCK OF


STATEMENTS OR PART OF A PROGRAM SEVERAL TIMES

--> TYPES: 1. SIMPLE LOOP

2. WHILE LOOP
3. NUMERIC FOR
LOOP

4. CURSOR FOR
LOOP

SIMPLE LOOP:

-- EXIT CLAUSES: 1. EXIT


USING IF THEN

2. EXIT WHEN

SQL> LOOP
STATEMENT 1;
STATEMENT 2;
...
STATEMENT N;
END LOOP;

-- EXIT

SQL> DECLARE
V_COUNTER NUMBER :=
0;
V_RESULT NUMBER;
BEGIN
LOOP

V_COUNTER:=V_COUNTER + 1;
V_RESULT:= 19 *
V_COUNTER;

DBMS_OUTPUT.PUT_LINE('19'||' X '||V_COUNTER||' = '||V_RESULT);


IF V_COUNTER
>=10 THEN
EXIT;
END IF;
END LOOP;
END;

-- EXIT WHEN

SQL> DECLARE
V_COUNTER NUMBER :=
0;
V_RESULT NUMBER;
BEGIN
LOOP

V_COUNTER:=V_COUNTER + 1;
V_RESULT:= 19 *
V_COUNTER;

DBMS_OUTPUT.PUT_LINE('19'||' X '||V_COUNTER||' = '||V_RESULT);


EXIT WHEN
V_COUNTER >= 10
END LOOP;
END;
WHILE LOOP:

--SYNTAX: WHILE CONDITION LOOP


STATEMENT 1;
STATEMENT 2;
...
STATEMENT 3;
END LOOP;

SQL> DECLARE
V_COUNTER NUMBER :=
0;
V_RESULT NUMBER;
BEGIN
WHILE V_COUNTER <=
10 LOOP
V_RESULT:= 19 *
V_COUNTER;

DBMS_OUTPUT.PUT_LINE('19'||' X '||V_COUNTER||' = '||V_RESULT);

V_COUNTER:=V_COUNTER + 1;
END LOOP;
DBMS_OUTPUT.PUT_LINE('OUTSIDE THE
LOOP');
END;
/

SQL> DECLARE
V_TEST BOOLEAN := TRUE;
V_COUNTER NUMBER := 0;
BEGIN
WHILE V_TEST LOOP
V_COUNTER := V_COUNTER + 1;
DBMS_OUTPUT.PUT_LINE(V_COUNTER);
IF V_COUNTER = 10 THEN
V_TEST := FALSE;
END IF;
END LOOP;
DBMS_OUTPUT.PUT_LINE('OUTSIDE THE
LOOP');
END;
/

FOR LOOP: --> FOR LOOP ALLOWS


YOU TO EXECUTE THE BLOCK OF STATEMENTS REPEATEDLY FOR A FIXED NUMBER OF LINE

TYPES: 1. NUMERIC
FOR LOOP
2. CURSOR
FOR LOOP

1. NUMERIC FOR LOOP:

SYNTAX: FOR LOOP_COUNTER


IN [REVERSE] LOWER LIMIT .. UPPER LIMIT LOOP
STATEMENT 1;
STATEMENT
2;
...
STATEMENT
N;
END LOOP;

SQL> SET SERVEROUTPUT ON;

SQL> BEGIN
FOR V_COUNTER IN 1 ..
10 LOOP

DBMS_OUTPUT.PUT_LINE(V_COUNTER);
END LOOP;
END;

SQL> BEGIN
FOR V_COUNTER IN REVERSE 1 .. 10 LOOP
DBMS_OUTPUT.PUT_LINE(V_COUNTER);
END LOOP;
END;

SQL> DECLARE
V_RESULT NUMBER;
BEGIN
FOR V_COUNTER IN 1 ..
10 LOOP
V_RESULT := 19 * V_COUNTER;
DBMS_OUTPUT.PUT_LINE('19'||' X '||
V_COUNTER||' = '||V_RESULT);
END LOOP;
END;

TRIGGERS:
--> NAMED PL/SQL BLOCKS WHICH ARE STORED IN
THE DATABASE

--> SPECIALIZED STORED PROGRAMS WHICH


EXECUTE IMPLICITLY WHEN A TRIGGERING EVENT OCCURS

EVENTS: -- A DML STATEMENT


-- A DDL STATEMENT
-- A SYSTEM EVENT
-- A USER EVENT

TYPES OF TRIGGERS:
-- DML TRIGGERS
-- DDL TRIGGERS
-- SYSTEM/DB EVENT TRIGGERS
-- INSTEAD-OF TRIGGERS

-- COMPOUND TRIGGERS

SYNTAX: CREATE [OR REPLACE] TRIGGER


<TRIGGER_NAME>
{BEFORE | AFTER}
TRIGGERING_EVENT ON <TABLE_NAME>
[FOR EACH ROW] [FOLLOWS
ANOTHER_TRIGGER_NAME]
[ENABLE/DISABLE] [WHEN
CONDITION]
DECLARE
DECLARATION STATEMENTS
BEGIN
EXECUTABLE STATEMENTS
END;

USES: --> ENFORCES BUSINESS RULES


--> GAIN STRONG CONTROL OVER THE
SECURITY
--> COLLECT STATISTICAL
INFORMATION
--> AUTOMATICALLY GENERATE
VALUES
--> PREVENT INVALID TRANSATIONS

1. DML TRIGGERS:

SQL> CREATE TABLE SUPERHEROS


(
SH_NAME VARCHAR2(30)
);

SQL> SET SERVEROUTPUT ON;

SQL> CREATE OR REPLACE TRIGGER


BI_SUPERHEROS
BEFORE INSERT ON SUPERHEROS
FOR EACH ROW
ENABLE
DECLARE
V_USER VARCHAR2(30);
BEGIN
SELECT USER INTO V_USER
FROM DUAL;

DBMS_OUTPUT.PUT_LINE('YOU JUST INSERTED A LINE MR. '||V_USER);


END;
/

SQL> CREATE OR REPLACE TRIGGER


BU_SUPERHEROS
BEFORE UPDATE ON SUPERHEROS
FOR EACH ROW
ENABLE
DECLARE
V_USER VARCHAR2(30);
BEGIN
SELECT USER INTO V_USER FROM DUAL;
DBMS_OUTPUT.PUT_LINE('YOU JUST UPDATED A
LINE MR. '||V_USER);
END;
/

SQL> CREATE OR REPLACE TRIGGER TR_SUPERHEROS


BEFORE INSERT OR DELETE OR
UPDATE ON SUPERHEROS
FOR EACH ROW
ENABLE
DECLARE
V_USER VARCHAR2(30);
BEGIN
SELECT USER INTO V_USER
FROM DUAL;
IF INSERTING THEN

DBMS_OUTPUT.PUT_LINE('ONE ROW INSERTED BY '||V_USER);


ELSIF DELETING THEN

DBMS_OUTPUT.PUT_LINE('ONE ROW DELETED BY '||V_USER);


ELSIF UPDATING THEN

DBMS_OUTPUT.PUT_LINE('ONE ROW UPDATED BY '||V_USER);


END IF;
END;
/

--- AUDITING

SQL> CREATE TABLE SH_AUDIT


(NEW_NAME VARCHAR2(30),
OLD_NAME VARCHAR2(30),
USER_NAME VARCHAR2(30),
ENTRY_DATE VARCHAR2(30),
OPERATION VARCHAR2(30)
);

SQL> CREATE OR REPLACE TRIGGER


SUPERHEROS_AUDIT
BEFORE INSERT OR DELETE OR
UPDATE ON SUPERHEROS
FOR EACH ROW
ENABLE
DECLARE
V_USER VARCHAR2(30);
V_DATE VARCHAR2(30);
BEGIN
SELECT USER,
TO_CHAR(SYSDATE,'DD/MON/YYYY HH24:MI:SS') INTO V_USER, V_DATE FROM DUAL;
IF INSERTING THEN
INSERT INTO
SH_AUDIT(NEW_NAME, OLD_NAME, USER_NAME, ENTRY_DATE, OPERATION)

VALUES(:NEW.SH_NAME, NULL, V_USER, V_DATE, 'INSERT');


ELSIF DELETING THEN
INSERT INTO
SH_AUDIT(NEW_NAME, OLD_NAME, USER_NAME, ENTRY_DATE, OPERATION)
VALUES(NULL,
:OLD.SH_NAME, V_USER, V_DATE, 'DELETE');
ELSIF UPDATING THEN
INSERT INTO
SH_AUDIT(NEW_NAME, OLD_NAME, USER_NAME, ENTRY_DATE, OPERATION)

VALUES(:NEW.SH_NAME, :OLD.SH_NAME, V_USER, V_DATE, 'UPDATE');


END IF;
END;
/

--- BACKUP AND SYNCHRONIZING BACKUP


TABLE

SQL> DESC SUPERHEROS;

SQL> CRAETE TABLE SUPERHEROS_BACKUP


AS SELECT * FROM SUPERHEROS WHERE 1=2;

SQL> CREATE OR REPLACE TRIGGER


SUPERHEROS_BACKUP
BEFORE INSERT OR DELETE OR
UPDATE ON SUPERHEROS
FOR EACH ROW
ENABLE
BEGIN
IF INSERTING THEN
INSERT INTO
SUPERHEROS_BACKUP(SH_NAME) VALUES(:NEW.SH_NAME);
ELSIF DELETING THEN
DELETE FROM
SUPERHEROS_BACKUP WHERE SH_NAME= :OLD.SH_NAME;
ELSIF UPDATING THEN
UPDATE
SUPERHEROS_BACKUP SET SH_NAME = :NEW.SH_NAME WHERE SH_NAME = :OLD.SH_NAME;
END IF;
END;
/

2. DDL TRIGGERS:

SQL> SHOW USER;

SQL> CREATE TABLE SCHEMA_AUDIT


(DDL_DATE DATE,
DDL_USER VARCHAR2(15),
OBJECT_CREATED
VARCHAR2(15),
OBJECT_NAME VARCHAR2(15),
DDL_OPERATION VARCHAR2(15)
);

--- FOR SCHEMA

SQL> CREATE OR REPLACE TRIGGER


HR_AUDIT_TR
AFTER DDL ON SCHEMA
BEGIN
INSERT INTO SCHEMA_AUDIT
VALUES
(SYSDATE,

SYS_CONTEXT('USERENV','CURRENT_USER'), # <SYS_CONTEXT(NAMESPACE, PARAMETER,


LENGTH)>
ORA_DICT_OBJ_TYPE,
ORA_DICT_OBJ_NAME,
ORA_SYSEVENT
);
END;
/

--- FOR DATABASE

SQL> CREATE OR REPLACE TRIGGER


DB_AUDIT_TR
AFTER DDL ON DATABASE
BEGIN
INSERT INTO SCHEMA_AUDIT
VALUES
(SYSDATE,

SYS_CONTEXT('USERENV','CURRENT_USER'), # <SYS_CONTEXT(NAMESPACE, PARAMETER,


LENGTH)>
ORA_DICT_OBJ_TYPE,
ORA_DICT_OBJ_NAME,
ORA_SYSEVENT
);
END;
/

3. DATABASE EVENT:

-- DATABASE EVENT TRIGGERS COME INTO


ACTION WHEN SOME SYSTEM EVENT OCCURS SUCH AS
1. DATABASE LOG ON
2. LOG OFF
3. START UP OR
4. SHUT DOWN

-- DATABASE EVENT TRIGGERS CAN BE


CREATED TO MONITOR THE SYSTEM EVENT ACTIVITIE OF EITHER A SPECIFIC
1. USER OR
2. A WHOLE DATABASE

-- ANY USER OF YOUR DATABASE CAN


CREATE A DATABASE EVENT TRIGGER IN ITS OWN SCHEMA IF IT HAS CREATE TRIGGER
PRIVILEGE

-- TO CREATE A TRIGGER ON THE


DATABASE YOU MUST NEED ADMINISTRATIVE DATABASE TRIGGER SYSTEM PRIVIILEGES

SYNTAX: CREATE OR REPLACE TRIGGER


TRIGGER_NAME
BEFORE | AFTER
DATABASE_EVENT ON DATABASE/SCHEMA
BEGIN
PL/SQL CODE
END;
/

SQL> CREATE TABLE SCOTT_EVNT_AUDIT


(EVENT_TYPE VARCHAR2(20),
LOGON_DATE DATE,
LOGON_TIME VARCHAR2(15),
LOGOF_DATE DATE,
LOGOF_TIME VARCHAR2(15)
);

--- LOG ON EVENT

SQL> CREATE OR REPLACE TRIGGER


SCOTT_LGON_AUDIT
AFTER LOGON ON SCHEMA
BEGIN
INSERT INTO
SCOTT_EVNT_AUDIT VALUES
(ORA_SYSEVENT,
SYSDATE,
TO_CHAR(SYSDATE,
'HH24:MI:SS'),
NULL,
NULL
);
COMMIT;
END;
/

SQL> CREATE TABLE SCOTT_AUDIT


(EVENT_TYPE VARCHAR2(20),
LOGON_DATE DATE,
LOGON_TIME VARCHAR2(15),
LOGOF_DATE DATE,
LOGOF_TIME VARCHAR2(15)
);

SQL> TRUNCATE TABLE SCOTT_AUDIT;

SQL> SELECT * FROM SCOTT_AUDIT;

--- LOGOFF EVENT

SQL> CREATE OR REPLACE TRIGGER S_LGOF_AUDIT


BEFORE LOGOFF ON SCHEMA
BEGIN
INSERT INTO SCOTT_AUDIT VALUES
(ORA_SYSEVENT,
NULL,
NULL,
SYSDATE,
TO_CHAR(SYSDATE, 'HH24:MI:SS')
);
COMMIT;
END;
/

SQL> CREATE TABLE DB_EVNT_AUDIT


(USER_NAME VARCHAR2(15),
EVENT_TYPE VARCHAR2(20),
LOGON_DATE DATE,
LOGON_TIME VARCHAR2(15),
LOGOF_DATE DATE,
LOGOF_TIME VARCHAR2(15)
);
--- DATABASE LOGOFF EVENT

SQL> CREATE OR REPLACE TRIGGER


DB_LGOF_AUDIT
AFTER LOGOFF ON DATABASE
BEGIN
INSERT INTO
DB_EVNT_AUDIT VALUES
(USER,
ORA_SYSEVENT,
SYSDATE,
NULL,
NULL,
TO_CHAR(SYSDATE,
'HH24:MI:SS')
);
COMMIT;
END;
/

--- DATABASE STARTUP TRIGGER

SQL> CREATE TABLE STARTUP_AUDIT


(EVENT_TYPE VARCHAR2(30),
EVENT_DATE DATE,
EVENT_TIME VARCHAR2(15)
);

SQL> CREATE OR REPLACE TRIGGER


TR_STARTUP_AUDIT
AFTER STARTUP ON DATABASE
BEGIN
INSERT INTO STARTUP_AUDIT VALUES
(ORA_SYSEVENT,
SYSDATE,
TO_CHAR(SYSDATE, 'HH24:MI:SS')
);
END;
/

4. INSTEAD-OF TRIGGERS

-- USING INSTEAD-OF TRIGGER YOU CAN


CONTROL THE DEFAULT BEHAVIOUR OF INSERT, DELETE, UPDATE AND MERGE OPERATIONS ON
VIEWS BUT NOT ON TABLES

-- WE CAN USE THEM TO MAKE NON-UPDATABLE VIEW TO


UPDATABLE

-- OVERRIDE THE DEFAULT BEHAVIOUR OF VIEWS THAT ARE


UPDATABLE

SYNTAX: CREATE OR REPLACE TRIGGER TRIGGER_NAME


INSTEAD OF OPERATION
ON VIEW_NAME
FOR EACH ROW
BEGIN
---PL/SQL CODE---
END;
/
--- INSTEAD-OF INSERT

SQL> CREATE TABLE TRAINER


(
FULL_NAME VARCHAR2(30)
);

SQL> CREATE TABLE SUBJECT


(
SUBJECT_NAME VARCHAR2(20)
);

SQL> INSERT INTO TRAINER VALUES ('KARTHIK


KONANKI');

SQL> INSERT INTO SUBJECT VALUES ('ORACLE PL/SQL');

SQL> CREATE VIEW VW_COURSE AS


SELECT FULL_NAME, SUBJECT_NAME FROM TRAINER,
SUBJECT;

SQL> INSERT INTO VW_COURSE VALUES ('KARTHIK',


'SAS');

SQL> CREATE OR REPLACE TRIGGER TR_IO_INSERT


INSTEAD OF INSERT ON VW_COURSE
FOR EACH ROW
BEGIN
INSERT INTO TRAINER (FULL_NAME) VALUES
(:NEW.FULL_NAME);
INSERT INTO SUBJECT (SUBJECT_NAME) VALUES
(:NEW.SUBJECT_NAME);
END;
/

--- INSTEAD-OF UPDATE

SQL> CREATE OR REPLACE TRIGGER IO_UPDATE


INSTEAD OF UPDATE ON VW_COURSE
FOR EACH ROW
BEGIN
UPDATE TRAINER SET FULL_NAME =
:NEW.FULL_NAME
WHERE FULL_NAME =
:OLD.FULL_NAME;
UPDATE SUBJECT SET
SUBJECT_NAME = :NEW.SUBJECT_NAME
WHERE SUBJECT_NAME =
:OLD.SUBJECT_NAME;
END;
/

SQL> UPDATE VW_COURSE SET FULL_NAME


= 'SURESH' WHERE FULL_NAME = 'KARTHIK';
--- INCASE OF COMPLEX VIEW WHICH
YOU HAVE CREATED ON MULTIPLE TABLES, IT IS ADVISABLE TO USE INSTEAD OF TRIGGER SO
AS TO SUPPORT THE
INSERTS, DELETES AND UPDATES
THAT REFERENCE THE DATA IN MULTIPLE TABLES

--- INSTEAD-OF DELETE TRIGGER

SQL> CREATE OR REPLACE TRIGGER


IO_DELETE
INSTEAD OF DELETE ON VW_COURSE
FOR EACH ROW
BEGIN
DELETE FROM TRAINER
WHERE FULL_NAME = :OLD.FULL_NAME;
DELETE FROM SUBJECT
WHERE SUBJECT_NAME = :OLD.SUBJECT_NAME;
END;
/

CURSORS IN PL\SQL:

-- CURSOR IS POINTER TO MEMORY AREA


CALLED CONTEXT AREA

-- CONTEXT AREA IS A MEMORY REGION


INSIDE THE PROCESS GLOBAL AREA OR PGA

-- ASSIGNED TO HOLD THE INFORMATION


ABOUT THE PROCESSING OF A SELECT STATEMENT OR DML STATEMENT

-- CONTEXT AREA IS A MEMORY REGION


INSIDE THE PGA WHICH HELPS ORACLE SERVER IN PROCESSING AN SQL STATEMENT
BY HOLDING THE IMPORTANT
INFORMATION ABOUT THAT STATEMENT.

-- INFORMATION: 1. ROWS RETURNED BY


A QUERY
2. NUMBER OF ROWS
PROCESSED BY A QUERY
3. A POINTER
TO THE PARSED QUERY IN THE SHARED POOL

-- USING CURSOR YOU CAN CONTROL THE


CONTEXT AREA AS IT IS A POINTER TO THE SAME

TYPES OF CURSOR: 1. IMPLICIT CURSOR


2. EXPLICIT CURSOR

1. IMPLICIT CURSOR: --
AUTOMATICALLY CREATED BY THE ORACLE SERVER
-- USER CANNOT
CONTROL THE BEHAVIOUR OF THESE CURSORS
--
ORACLE SERVER CREATES AN IMPLICIT CURSOR FOR ANY PL/SQL BLOCK WHICH AN SQL
STATEMENT
-- AS
LONG AS AN EXPLICT CURSOR DOESNOT EXIST FOR THAT SQL STATEMENT
2. EXPLICIT CURSOR: -- EXPILICT
CURSORS ARE USER DEFINED CURSORS
-- USER HAS
FULL CONTROL OF EXPLICIT CURSOR

STEPS FOR CREATEING AN EXPLICIT


CURSOR:

----------------------------------------------------
| |
| |
|
| | |
|
| | |
DECLARE
| | |

| | |

| | |

OPEN | |

| |

| |

FETCH |

CLOSE

1. DECLARE: -- DECLARING A CURSOR MEANS


INITIALIZING A CURSOR INTO A MEMORY
-- YOU DEFINE EXPLICIT
CURSOR IN DECLARATION SECTION OF YOUR PL/SQL BLOCK

SYNTAX: CURSOR CURSOR_NAME IS


SELECT_STATEMENT;

2. OPEN: -- IN ORDER TO PUT THE


CURSOR TO WORK WE HAVE TO OPEN IT FIRST
-- WHEN YOU OPEN A CURSOR
THE MEMORY WILL BE ALLOTED TO IT

SYNTAX: OPEN CURSOR_NAME;

3. FETCH: -- THE PROCESS OF


RETRIEVING THE DATA FROM THE CURSOR IS CALLED FETCHING

SYNTAX: FETCH CURSOR_NAME INTO


PL/SQL VARIABLE; OR FETCH CURSOR_NAME INTO PL/SQL RECORD;

4. CLOSE: -- WHEN THE SERVER COMES


ACROSS THE CLOSING STATEMENT OF A CURSOR IT WILL RELINQUISH ALL THE RESOURCES
ASSOCIATED WITH IT

SYNTAX: CLOSE CURSOR_NAME;

--- EXPLICT CURSOR:

SQL> SET SERVEROUTPUT ON;

SQL> DECLARE
V_NAME VARCHAR2(30);
CURSOR CUR_SCOTT IS
SELECT FIRST_NAME FROM EMPLOYEES
WHERE EMPLOYEE_ID < 105;
BEGIN
OPEN CUR_SCOTT
LOOP
FETCH CUR_SCOTT INTO V_NAME;
DBMS_OUTPUT.PUT_LINE(V_NAME);
EXIT WHEN CUR_SCOTT%NOTFOUND;
END LOOP;
CLOSE CUR_SCOTT;
END;

--- CURSOR ATTRIBUTE %NOTFOUND IS A BOOLEAN


ATTRIBUTE WHICH RETURNS TRUE ONLY WHEN PREVIOUS FETCH COMMAND
OF THE CURSOR DID NOT RETURN A ROW

--- CURSOR PARAMETERS

SQL> SET SERVEROUTPUT ON;

SQL> DECLARE
V_NAME VARCHAR2(30);
CURSOR P_CUR_SCOTT (VAR_E_ID VARCHAR2) IS
SELECT FIRST_NAME FROM EMPLOYEES
WHERE EMPLOYEE_ID < VAR_E_ID;
BEGIN
OPEN P_CUR_SCOTT(105);
LOOP
FETCH P_CUR_SCOTT INTO V_NAME;
EXIT WHEN P_CUR_SCOTT%NOTFOUND;

DBMS_OUTPUT.PUT_LINE(V_NAME);
END LOOP;
CLOSE P_CUR_SCOTT;
END;
/

SQL> DECLARE
V_NAME VARCHAR2(30);
V_EID NUMBER(10);
CURSOR CUR_SCOTT(VAR_ID NUMBER := 190) IS
SELECT FIRST_NAME, EMPLOYEE_ID FROM
EMPLOYEES
WHERE EMPLOYEE_ID > VAR_ID;
BEGIN
OPEN CUR_SCOTT;
LOOP
FETCH CUR_SCOTT INTO V_NAME, V_EID;
EXIT WHEN CUR_SCOTT%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(V_NAME||' '||
V_EID);
END LOOP;
END;
/
--- CURSOR FOR LOOP

SYNTAX: FOR LOOP_INDEX IN


CURSOR_NAME
LOOP
STATEMENTS
END LOOP;

SQL> DECLARE
CURSOR CUR_SCOTT IS
SELECT FIRST_NAME, LAST_NAME FROM
EMPLOYEES
WHERE EMPLOYEE_ID > 200;
BEGIN
FOR L_IDX IN CUR_SCOTT
LOOP

DBMS_OUTPUT.PUT_LINE(L_IDX.FIRST_NAME||' '||L_IDX.LAST_NAME);
END LOOP;
END;
/

--- CURSOR FOR LOOP WITH


PARAMETERIZED CURSOR

SQL> DECLARE
CURSOR CUR_SCOTT(VAR_ID NUMBER) IS
SELECT FIRST_NAME, LAST_NAME FROM
EMPLOYEES
WHERE EMPLOYEE_ID > (VAR_ID);
BEGIN
FOR L_IDX IN CUR_SCOTT
LOOP

DBMS_OUTPUT.PUT_LINE(L_IDX.FIRST_NAME||' '||L_IDX.LAST_NAME);
END LOOP;
END;
/

SPECIAL DATA TYPES: 1. ANCHORED DATATYPE


2. RECORD DATATYPE

2. RECORD DATATYPE: -- RECORDS ARE


COMPOSITE DATA STRUCTURES MADE UP OF DIFFERENT COMPONENTS CALLED FIELDS
-- THESE FEILDS
CAN HAVE DIFFERENT DATATYPES
-- A
RECORD IS A GROUP OF RELATED DATA ITEMS STORED IN FIELDS, EACH WITH ITS OWN NAME
AND DATATYPE
TYPES OF RECORDS: 1. TABLE BASED RECORD
2. CURSOR BASED RECORD
3. USER DEFINED
RECORD

SYNTAX: VARIABLE_NAME TABLE_NAME


%ROWTYPE; ---> TABLE BASED RECORD
VARIABLE_NAME CURSOR_NAME
%ROWTYPE; ---> CURSOR BASED RECORD

SQL> SET SERVEROUTPUT ON;

SQL> DECLARE
V_FNAME VARCHAR2(20);
V_SALARY VARCHAR2(8);
BEGIN
SELECT FIRST_NAME,
SALARY INTO V_FNAME, V_SALARY
FROM EMPLOYEES WHERE
EMPLOYEE_ID = 200;

DBMS_OUTPUT.PUT_LINE(V_FNAME||' '||V_SALARY);
END;
/

1. TABLE BASED RECORD DATATYPE

SQL> DECLARE
V_EMP EMPLOYEES%ROWTYPE;
BEGIN
SELECT * INTO V_EMP
FROM EMPLOYEES WHERE EMPLOYEE_ID = 200;

DBMS_OUTPUT.PUT_LINE(V_EMP.FIRST_NAME||' '||V_EMP.SALARY);
END;
/

SQL> DECLARE
V_EMP EMPLOYEES%ROWTYPE;
BEGIN
SELECT FIRST_NAME INTO V_EMP.FIRST_NAME
FROM EMPLOYEES WHERE EMPLOYEE_ID = 200;
DBMS_OUTPUT.PUT_LINE(V_EMP.FIRST_NAME);
END;
/

SQL> DECLARE
V_EMP EMPLOYEES%ROWTYPE;
BEGIN
SELECT FIRST_NAME, SALARY INTO
V_EMP.FIRST_NAME, V_EMP.SALARY
FROM EMPLOYEES WHERE EMPLOYEE_ID = 200;
DBMS_OUTPUT.PUT_LINE(V_EMP.FIRST_NAME||'
'||V_EMP.SALARY);
END;
/

2. CURSOR BASED RECORD DATATYPE


-- CURSOR BASED RECORDS ARE THOSE
VARIABLES WHOSE STRUCTURE IS DERIVED FROM SELECT LIST OF AN ALREADY CREATED CURSOR

-- IN THE CASE OF CURSOR BASED


RECORD THESE FIELDS ARE INITIALIZED BY FETCHING THE DATA FROM THE SELECT LIST OF
THE
CURSOR THAT WAS USED TO CREATE
THIS VARIABLE

-- CREATION OF CURSOR BASED RECORD:


1. DECLARATION
OF CURSOR BASED RECORD
2.
INITIALIZATION OF CURSOR BASED RECORD
3. ACESSING
DATA STORED INTO THE CURSOR BASED RECORD VARIABLE

SQL> SET SERVEROUTPUT ON;

SQL> DECLARE
CURSOR CUR_SCOTT IS
SELECT FIRST_NAME, SALARY FROM EMPLOYEES
WHERE EMPLOYEE_ID = 100;

V_EMP CUR_SCOTT%ROWTYPE;
BEGIN
OPEN CUR_SCOTT;
FETCH CUR_SCOTT INTO V_EMP;
DBMS_OUTPUT.PUT_LINE(V_EMP.FIRST_NAME||'
'||V_EMP.SALARY);
CLOSE CUR_SCOTT;
END;
/

--- ASSIGN THE VALUE OF ONE RECORD VARIABLE TO


ANOTHER RECORD VARIABLE

SQL> DECLARE
CURSOR CUR_HR IS
SELECT FIRST_NAME, SALARY FROM EMPLOYEES
WHERE EMPLOYEE_ID = 100;
--cursor based record variable declare
V_EMP CUR_HR%ROWTYPE;
V_CUR V_EMP%TYPE;
BEGIN
OPEN CUR_HR;
FETCH CUR_HR INTO V_CUR;
DBMS_OUTPUT.PUT_LINE (V_CUR.FIRST_NAME);
DBMS_OUTPUT.PUT_LINE (V_CUR.SALARY);
CLOSE CUR_HR;
END;
/

SQL> DECLARE
CURSOR CUR_HR IS
SELECT FIRST_NAME,
SALARY FROM EMPLOYEES
WHERE EMPLOYEE_ID >
200;

V_EMP CUR_HR%ROWTYPE;
BEGIN
OPEN CUR_HR;
LOOP
FETCH CUR_HR INTO
V_EMP;
EXIT WHEN CUR_HR
%NOTFOUND;

DBMS_OUTPUT.PUT_LINE(V_EMP.FIRST_NAME||' '||V_EMP.SALARY);
END LOOP;
CLOSE CUR_HR;
END;
/
--- CAN WE SIMPLIFY THIS CODE?

--- IS THERE ANY OTHER WAY GETTING THE SAME RESULT


USING CURSORS AND RECORD VARIABLES. IF SO THEN WHAT IT IS?

3. USER DEFINED RECORD DATATYPE

-- USER DEFINED RECORDS


ARE THE RECORD VARIABLES WHOSE STRUCTURE IS DEFINED BY THE USER, WHICH IS UNLIKE
THE TABLE OR
CURSOR BASED RECORDS WHOSE STRUCTURES ARE DERIVED FROM THEIR RESPECTIVE TABLES OR
CURSOR

-- THIS MEANS THAT WITH


USER DEFINED RECORDS YOU CAN HAVE COMPLETE CONTROL OVER THE STRUCTURE OF YOUR
RECORD VARIABLE

SYNTAX: TYPE TYPE_NAME IS RECORD


(
FIELD_NAME1 DATATYPE 1,
FIELD_NAME2 DATATYPE 2,
....
FIELD_NAMEn DATATYPE n
);

RECORD_NAME TYPE_NAME;

SQL> SET SERVEROUTPUT ON;

SQL> DECLARE
TYPE RV_DEPT IS RECORD
(
F_NAME VARCHAR2(20),
D_NAME DEPARTMENTS.DEPARTMENT_NAME%TYPE
);
VAR1 RV_DEPT;
BEGIN
SELECT FIRST_NAME, DEPARTMENT_NAME INTO
VAR1.F_NAME, VAR1.D_NAME
FROM EMPLOYEES JOIN DEPARTMENTS USING
(DEPARTMENT_ID) WHERE EMPLOYEE_ID = 100;

DBMS_OUTPUT.PUT_LINE(VAR1.F_NAME||' '||
VAR1.D_NAME);
END;
/

PL/SQL FUNCTIONS:

-- SELF CONTAINED SUB-PROGRAM


THAT IS MEANT TO DO SOME SPECIFIC WELL DEFINED TASK.

-- FUNCTIONS ARE NAMED


PL/SQL BLOCKS WHICH MEANS THEY CAN BE STORED INTO THE DATABASE AS A DATABASE OBJECT
AND CAN BE REUSED

TYPES OF SUBROUTINES OR
SUB-PROGRAMS

1. PL/SQL FUNCTIONS

2. PL/SQL PROCEDURES

SYNTAX: CREATE OR REPLACE FUNCTION


FUNCTION_NAME
(PARAMETER1,
PARATMETER2,...) RETURN DATATYPE
IS
DECLARE VARIABLE,
CONSTANT ETC;
BEGIN
EXECUTABLE
STATEMENTS
RETURN(RETURN
VALUE);
END;
/

SQL>

PL/SQL STORED PROCEDURES:

-- A STORED PROCEDURE IS
A SELF CONTAINED SUB-PROGRAM THAT IS MEANT TO DO SOME SPECIFIC TASKS

-- YOU CANNAT USE A


PROCEDURE UNLIKE FUNCTIONS AS A RIGHT HAND SIDE OF OPARAND TO ASSIGNMENT OPERATOR
TO ASSIGN VALUE TO VARIABLE

-- VALUE RETURN BY
PROCEDURE CANNOT BE ASSIGN TO A VARIABLE

SYNTAX: CREATE OR REPLACE PROCEDURE


PRO_NAME(PARAMAETER1, PARAMETER2, ..)
IS [AUTHID DEFINER |
CURRENT_USER]
DECLARE STATEMENTS
BEGIN
EXECUTABLE
STATEMENTS
END PROCEDURE NAME;
/

SQL> CREATE OR REPLACE PROCEDURE


PR_HR IS
V_NAME VARCHAR2(20) :=
'KARTHIK KONANKI';
V_WEB VARCHAR2(20) :=
'KARTHIK_KONANKI.COM';
BEGIN
DBMS_OUTPUT.PUT_LINE('I AM
'||V_NAME||' FROM '||V_WEB);
END PR_HR;
/

SQL> SET SERVEROUTPUT ON;

SQL> EXECUTE PR_HR;

SQL> BEGIN
PR_HR;
END;
/
-- WRITE A STORED PROCEDURE AND TRY
CALLING IT USING A NAMED PL/SQL BLOCK SUCH AS PL\SQL FUNCTION OR TRIGGER

--- PARAMETERS

SQL> CREATE OR REPLACE PROCEDURE


EMP_SAL(DEPT_ID NUMBER, SAL_RAISE NUMBER)
IS
BEGIN
UPDATE EMPLOYEES SET SALARY= SALARY *
SAL_RAISE WHERE DEPARTMENT_ID = DEPT_ID;
END EMP_SAL;
/

CALLING NOTATION: -- CALLING NOTATION IS A WAY


OF PROVIDING VALUES TO THE PARAMETERS OF A SUBROUTINES SUCH AS PL/SQL
FUNCTION AND PROCEDURE

TYPES OF CALLING NOTATION:


1. POSITIONAL NOTATION
2. NAMED NOTATION
3. MIXED CALLING NOTATION

1. POSITIONAL NOTATION: IN
POSITIONAL NOTATION YOU HAVE TO SPECIFY THE VALUE FOR EACH FORMAL PARAMETER IN A
SEQUENTIAL MANNER

SQL> CREATE OR REPLACE PROCEDURE


EMP_SAL(DEPT_ID NUMBER, SAL_RAISE NUMBER)
IS
BEGIN
UPDATE EMPLOYEES SET SALARY= SALARY *
SAL_RAISE WHERE DEPARTMENT_ID = DEPT_ID;
DBMS_OUTPUT.PUT_LINE('SALARY UPDATED
SUCCESSFULLY')
END EMP_SAL;
/

2. NAMED NOTATION: -- NAMED CALLING


NOTATION LETS YOU PASS VALUES TO THE FOEMAL PARAMATERS USING THEIR NAME
-- IN ORDER TO
ASSIGN VALUES TO THE FORMAL PARAMETERS USING THEIR NAMES WE USE ASSIGNMENT
OPERATORS

FORMAL
PARAMETER => VALUE

SQL> CREATE OR REPLACE FUNCTION


ADD_NUM(VAR_1 NUMBER, VAR_2 NUMBER DEFAULT 0, VAR_3 NUMBER) RETURN NUMBER
IS
BEGIN
DBMS_OUTPUT.PUT_LINE('VAR_1 -> '||
VAR_1);

DBMS_OUTPUT.PUT_LINE('VAR_2 -> '|| VAR_2);


DBMS_OUTPUT.PUT_LINE('VAR_2 -> '||
VAR_2);
RETURN VAR_1 + VAR_2 +
VAR_3;
END;
/

PL/SQL PACKAGES:
-- STORED LIBRARIES IN THE DATABASE WHICH
ALLOWS US TO GROUP RELATED PL/SQL OBJECTS UNDER ONE NAME
-- PACKAGES ARE LOGICAL GROUPS OF RELATED
PL/SQL OBJECTS
-- PACKAGES ARE NAMED PL/SQL BLOCKS
-- PERMINENTLY STORED INTO THE DATABASE
SCHEMA
-- CAN BE REFERENCED OR REUSED BY PROGRAM
-- IT CAN INCLUDE STORED PROCEDURES, PL/SQL
FUNCTIONS, DATABASE CURSORS, TYPE DECLARATION

ARCHITECTURE: -- THE PACKAGE


SPECIFICATION(HEADER)
-- THE PACKAGE BODY

PACKAGE SPECIFICATION: -- IN THIS SECTION WE PUT


THE DECLARATION OF ALL THE PACKAGE ELEMENTS
-- WHAT EVER ELEMENTS WE
DECLARE HERE IN THIS SECTION ARE PUBLICALLY AVAILABLE AND CAN BE
REFERENCED OUTSIDE OF THE
PACKAGE

SYNTAX: CREATE OR REPLACE PACKAGE PACKAGE_NAME IS


DECLARATION OF ALL THE PACKAGE
ELEMENTS...;
END PACKAGE_NAME;

PACKAGE BODY: -- WE PROVIDE ACTUAL STRUCTURE TO ALL


THE PACKAGE ELEMENTS
-- A PACKAGE BODY CONTAINS THE
IMPLEMENTATION OF THE ELEMENTS LISTED IN THE PACKAGE SPECIFICATION
-- A PACKAGE BODY CAN CONTAIN BOTH
DECLARATION OF THE VARIABLE AS WELL AS THE DEFINITION OF ALL THE PACKAGE ELEMENTS
-- ANY PACKAGE ELEMENTS WHICH IS NOT
IN PACKAGE SPECIFICATION BUT CODED IN THE PACKAGE BODY IS CALLED PRIVATE PACKAGGE
ELEMENTS

SYNTAX: CREATE OR REPLACE PACKAGE BODY PACKAGE_NAME


IS
VARIABLE DECLARATION;
TYPE DECLARATION;
BEGIN
IMPLEMENTATION OF PACKAGE ELEMENTS...
END PACKAGE_NAME;
/

SQL> CREATE OR REPLACE PACKAGE PACKAGE_HR IS


FUNCTION PRNT_STRING RETURN VARCHAR2;
PROCEDURE P_SUPERHERO(F_NAME VARCHAR2,
L_NAME VARCHAR2);
END PACKAGE_HR;

SQL> CREATE OR REPLACE PACKAGE BODY PACKAGE_HR IS

FUNCTION PRNT_STRING RETURN VARCHAR2 IS


BEGIN
RETURN 'KARTHIK KONANKI';
END PRNT_STRING;

PROCEDURE P_SUPERHERO(F_NAME VARCHAR2,


L_NAME VARCHAR2) IS
BEGIN
INSERT INTO
NEW_SUPERHEROS(F_NAME, L_NAME) VALUES (F_NAME, L_NAME);
END;
END PACKAGE_HR;

SQL> SET SERVEROUTPUT ON;

SQL> BEGIN

DBMS_OUTPUT.PUT_LINE(PACKAGE_HR.PRNT_STRING);
END;

SQL> SELECT * FROM NEW_SUPERHEROS;

SQL> BEGIN
PACKAGE_HR.P_SUPERHERO('BLACK', 'WIDOW');
END;

EXCEPTION ERROR HANDLING IN PL/SQL:

-- ANY ABNORMAL CONDITION OR EVENT


THAT INTERRUPTS THE NORMAL FLOW OF YOUR PROGRAM'S INSTRUCTIONS AT
RUN TIME IS AN EXCEPTION

TYPES OF EXCEPTIONS:
1. SYSTEM DEFINED EXCEPTIONS
2. USER DEFINED EXCEPTIONS
1. SYSTEM DEFINED EXCEPTIONS: -- DEFINED AND
MAINTAINED INPLICITLY BY THE ORACLE SERVER
-- THESE ARE MAINLY
DEFINED IN THE ORACLE STANDARD PACKAGE
-- WHENEVER AN
EXCEPTIION OCCUR INSIDE THE PROGRAM, ORCALE SERVER MATCHES AND IDENTIFIES THE
APPROPRIATE
EXCEPTION FROM THE AVAILABLE SET OF EXCEPTIONS FROM ORACLE STANDARD PACKAGE

2. USER DEFINED EXCEPTIONS: -- THESE EXCEPTIONS ARE


RAISED EXPLICITLY IN THE PL/SQL BLOCK

DECLARE USER DEFINED EXCEPTION: -- 3 WAYS

1. USING VARIABLE OF EXCEPTION TYPE:


-- DECLARE A
USER DEFINED EXCEPTION BY DECLARING A VARIABLE OF EXCEPTION DATATYPE IN YOUR CODE
AND RAISE
IT EXPLICITLY IN YOUR PROGRAM USING RAISE STATEMENT

2. USING PRAGMA EXCEPTION_INIT FUNCTION:


-- USING
PRAGMA EXCEPTION_INIT FUNCTION YOU CAN MAP A NON-PREDEFINED ERROR NUMBER WITH THE
VARIABLE
OF
EXCEPTION DATATYPE

3. USING RAISE_APPLICATION_ERROR METHOD:


-- USING
THIS MENTHOD YOU CAN DECLARE A USER DEFINED EXCEPTION WITH YOUR OWN CUSTOMIZED
ERROR NUMBER
AND
MESSAGE

1. USING VARIABLE OF EXCEPTION TYPE:

1. DECLARE VARIABLE OF EXCEPTION DATATYPE

2. RAISE THE EXCEPTION


3. HANDLE THE
EXCEPTION

-- RAISE STATEMENT CHANGES THE NORMAL FLOW OF EXECUTION OF THE


CODE

-- AS SOON AS COMPLIER COME ACROSS A RAISE CONDITION IT TRANSFER


THE CONTROL OVER

TO THE EXCEPTION HANDLER

SQL> DECLARE
VAR_DIVIDEND NUMBER := 24;
VAR_DIVISOR NUMBER := 0;
VAR_RESULT NUMBER;
EX_DIVZERO EXCEPTION;
BEGIN
IF VAR_DIVISOR = 0 THEN
RAISE EX_DIVZERO;
END IF;
VAR_RESULT :=
VAR_DIVIDEND/VAR_DIVISOR;
DBMS_OUTPUT.PUT_LINE('RESULT = '||
VAR_RESULT);
EXCEPTION WHEN EX_DIVZERO THEN
DBMS_OUTPUT.PUT_LINE('ERROR ERROR! -
YOUR DIVISOR IS ZERO');
END;
/

2. USING RAISE_APPLICATION_ERROR
METHOD:
-- THIS
METHOD IS A PROCEDURE WHICH COMES IN-BUILT WITH ORACLE SOFTWARE

-- USING THIS PROCEDURE YOU CAN ASSSOCIATE AN ERROR NUMBER WITH THE CUSTOM
ERROR MESSAGE

-- COMBINING BOTH THE ERROR NUMBER AND CUSTOM ERROR MESSAGE YOU CAN COMPOSE
AN ERROR STRING
WHICH LOOK SIMILAR
TO THOSE DEFAULT ERROR STRINGS WHICH ARE DISPLAYED BY ORACLE ENGINE
WHEN ERROR OCCURS

SQL> ACCEPT VAR_AGE NUMBER PROMPT


'WHAT IS YOUR AGE?';

DECLARE
AGE NUMBER := &VAR_AGE;
BEGIN
IF AGE < 18 THEN
RAISE_APPLICATION_ERROR(-20008, 'You
should be 18 or above for the drinks!'); --NUMBER SHOULD BE -20000 TO -20999
END IF;
DBMS_OUTPUT.PUT_LINE('Sure, What
would you like to have?');
EXCEPTION WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(SQLERRM);
END;
/

3. USING PRAGMA EXCEPTION_INIT FUNCTION:


-- USING THIS METHOD WE
CAN ASSOCIATE AN EXCEPTION NAME WITH AN ORACLE ERROR NUMBER
-- WE CAN USE THAT NAME
IN DESIGNING THE EXCEPTION HANDLER FOR THE ERROR

SQL> ACCEPT VAR_AGE NUMBER PROMPT


'WHAT IS YOUR AGE?';
DECLARE
EX_AGE EXCEPTION;
AGE NUMBER := &VAR_AGE;
PRAGMA EXCEPTION_INIT (EX_AGE, -20008);
BEGIN
IF AGE < 18 THEN
RAISE_APPLICATION_ERROR(-20008, 'You
should be 18 or above for the drinks!');
END IF;
DBMS_OUTPUT.PUT_LINE('Sure, What would
you like to have?');
EXCEPTION WHEN EX_AGE THEN
DBMS_OUTPUT.PUT_LINE(SQLERRM);
END;
/

COLLECTIONS IN PL/SQL:
-- A HOMOGENEOUS SINGLE DIMENSION
DATA STRUCTURE WHICH IS MADE OF ELEMENTS OF SAME DATATYPE IS
CALLED COLLECTION IN ORACLE
DATABASE
-- AN ARRAY IN ORACLE DATABASE

-- THE STRUCTURE OF PL/SQL


COLLECTIONS CONSIST OF A CELL WHICH SUBSCRIPT CALLED INDEX
-- DATA IS STORED INTO THESE
CELLS AND CAN BE IDENTIFIED AND ACCESSED USING THE INDEX NUMBER
-- UNLIKE ARRAY PL/SQL
COLLECTIONS ARE STRICTY ONE DIMENSIONAL

TYPES OF COLLECTIONS: 1. PERSISTANT


--
PERSISTANT COLLECTION, ARE THOSE WHICH STORE THE COLLECTION STRUCTURE WITH THE
DATA, PHYSICALLY

INTO THE DATABASE AND CAN BE ACCESSED AGAIN, IF NEEDED


A.
NESTED TABLES
B. VARRAYs

2. NON PERSISTANT

-- NON-PERSISTANT COLLECTION ONLY STORES DATA AND STRUCTURE JUST FOR ONE SESSION
A. ASSOCIATIVE

1. NESTED TABLE COLLECTIONS:


-- ONE DIMENSIONAL
STRUCTURE WHICH ARE PERSISTENT AND UNBOUNDED IN NATURE
-- THEY ARE ACCESSIBLE
IN SQL AND PL/SQL AND CAN BE USED IN TABLES, RECORDS AND OBJECT DEFINITIONS
-- SINCE IT IS AN
UNBOUNDED PL/SQL COLLECTION HENCE IT CAN HOLD ANY NUMBER OF ELEMENTS IN AN
UNORDERED SET

SYNTAX FOR PL\SQL BLOCK:


DECLARE

TYPE
NESTED_TABLE_NAME IS TABLE OF ELEMENT_TYPE[NOT NULL];

SQL> SET SERVEROUTPUT ON;


SQL> DECLARE
TYPE NEST_TABLE IS TABLE
OF NUMBER;
VAR_NT NEST_TABLE :=
NEST_TABLE(9, 18, 27, 36, 45, 54, 63, 72, 81, 90);
BEGIN

DBMS_OUTPUT.PUT_LINE('VALUE STORED AT INDEX 1 IS '||VAR_NT(1));


END;
/

SQL> DECLARE
TYPE NEST_TABLE IS TABLE
OF NUMBER;
VAR_NT NEST_TABLE :=
NEST_TABLE(9, 18, 27, 36, 45, 54, 63, 72, 81, 90);
BEGIN
FOR I IN 1..VAR_NT.COUNT
LOOP

DBMS_OUTPUT.PUT_LINE('VALUE STORED AT INDEX '||I||' IS '||VAR_NT(I));


END LOOP;
END;
/
-- PL/SQL NESTED TABLE AS DATABASE COLLECTION
OBJECT:

SQL> SET SERVEROUTPUT ON;

SQL> CREATE OR REPLACE TYPE


NEST_TABLE IS TABLE OF VARCHAR2(10);
/

SQL> CREATE TABLE MY_SUBJECT


(
SUB_ID NUMBER,
SUB_NAME VARCHAR2(20),
SUB_SCHEDULE_DAY NEST_TABLE
) NESTED TABLE ;

-- CREATING NESTED TABLES USING


USER DEFINE DATATYPE

SQL> SET SERVEROUTPUT ON;

SQL> CREATE OR REPLACE TYPE OBJECT_TYPE AS OBJECT


(
OBJ_ID NUMBER,
OBJ_NAME VARCHAR2(20)
);
/

SQL> CREATE OR REPLACE TYPE MY_NT IS TABLE OF


OBJECT_TYPE;
/

SQL> CREATE TABLE BASE_TABLE


(
TAB_ID NUMBER,
TAB_ELE MY_NT
) NESTED TABLE TAB_ELE STORE AS STORE_TAB_1;
/

2. VARRAY TABLE COLLECTON:


-- ACRONYM - VARIABLE
SIZED ARRAY
-- MODIFIED FORMAT OF
NESTED TABLE IN STORAGE

-- UNLIKE NESTED TABLE WHICH REQUIRES AN EXTERNAL TABLE FOR ITS STOREAGE

-- VARRAYs ARE STORED IN-LINE WITH THEIR PARENT RECORDS AS RAW VALUE IN THE PARENT
TABLE

SYNTAX FOR DB OBJECT: CREATE OR


REPLACE TYPE TYPE_NAME
IS {VARRAY |
VARYING ARRAY} (SIZE LIMIT)
OF
ELEMENT_TYPE;

SYNTAX FOR PL/SQL BLOCK: DECLARE


TYPE
TYPE_NAME IS {VARRAY | VARYING ARRAY}

(SIZE LIMIT) OF ELEMENT_TYPE;

MODIFY SIZE LIMIT:


ALTER TYPE
TYPE_NAME MODIFY LIMIT NEW_SIZE_LIMIT[INVALIDATE | CASCADE]

-- VARRAYs AS PL/SQL BLOCK

SQL> SET SERVEROUTPUT ON;

SQL> DECLARE
TYPE INBLOCK_VRY IS VARRAY(5) OF NUMBER;
VRY_OBJ INBLOCK_VRY := INBLOCK_VRY(NULL,
NULL, NULL, NULL, NULL);
BEGIN
FOR I IN 1..VRY_OBJ.LIMIT
LOOP
VRY_OBJ(I) := 10*I;
DBMS_OUTPUT.PUT_LINE(VRY_OBJ(I));
END LOOP;
END;
/

SQL> SET SERVEROUTPUT ON;

SQL> DECLARE
TYPE INBLOCK_VRY IS VARRAY(5) OF NUMBER;
VRY_OBJ INBLOCK_VRY := INBLOCK_VRY();
BEGIN
VRY_OBJ.EXTEND(5);
FOR I IN 1..VRY_OBJ.LIMIT
LOOP
VRY_OBJ(I) := 10*I;
DBMS_OUTPUT.PUT_LINE(VRY_OBJ(I));
END LOOP;
END;
/

SQL> SET SERVEROUTPUT ON;

SQL> DECLARE
TYPE INBLOCK_VRY IS VARRAY(5) OF NUMBER;
VRY_OBJ INBLOCK_VRY := INBLOCK_VRY();
BEGIN
FOR I IN 1..VRY_OBJ.LIMIT
LOOP
VRY_OBJ.EXTEND;
VRY_OBJ(I) := 10*I;
DBMS_OUTPUT.PUT_LINE(VRY_OBJ(I));
END LOOP;
END;
/

--- VARRAY AS DATABASE OBJECT

SQL> SET SERVEROUTPUT ON;

SQL> CREATE OR REPLACE TYPE


DBOBJ_VRY IS VARRAY(5) OF NUMBER;

SQL> CREATE TABLE CALANDER


(
DAY_NAME VARCHAR2(25),
DAY_DATE DBOBJ_VRY
);

SQL> INSERT INTO CALANDER (DAY_NAME, DAY_DATE)


VALUES('SUNDAY', DBOBJ_VRY(7, 14, 21, 28));

SQL> SELECT * FROM CALANDER;

SQL> SELECT TAB1.DAY_NAME,


VRY.COLUMN_NAME FROM CALANDER TAB1, TABLE(TAB1.DAY_DATE)VRY;

1. ASSSOCIATED ARRAY:
-- NON-
PERSISTENT

SQL> SET SERVEROUTPUT ON;

SQL> SET SERVEROUTPUT ON;

DECLARE
TYPE BOOKS IS TABLE OF NUMBER
INDEX BY VARCHAR2(20);
ISBN BOOKS;
BEGIN
ISBN('ORACLE DATABASE') := 1234;
ISBN('MYSQL') := 9876;
ISBN('MUSQL') := 1010;
DBMS_OUTPUT.PUT_LINE('VALUE '||
ISBN('ORACLE DATABASE'));
END;
/
SQL> SET SERVEROUTPUT ON;

SQL> DECLARE
TYPE BOOKS IS TABLE OF NUMBER
INDEX BY VARCHAR2(20);
ISBN BOOKS;
FLAG VARCHAR2(20);
BEGIN
ISBN('ORACLE DATABASE') := 1234;
ISBN('MYSQL') := 9876;
ISBN('MYSQL') := 1010;
FLAG := ISBN.FIRST;
WHILE FLAG IS NOT NULL
LOOP
DBMS_OUTPUT.PUT_LINE('KEY -> '||
FLAG||' VALUE -> '||ISBN(FLAG));
FLAG := ISBN.NEXT(FLAG);
END LOOP;
END;
/
COLLECTION METHODS:
-- COLLECTION METHODS ARE PL/SQL'S
BUILT-IN FUNCTIONS AND PROCEDURES WHICH CAN BE USED IN CONJUNCTION
WITH COLLECTION
-- USING PL/SQL COLLECTION METHOD YOU
CAN GET THE INFORMATION AS WELL AS ALTER THE CONTENT OF THE COLLECTION
-- IN ORACLE DATABASE WE HAVE 3
COLLECTION PROCEDURES AND 7 COLLECTION FUNCTIONS. IN TOTAL WE HAVE 10
COLLECTION METHODS
-- FUNCTIONS: 1. COUNT
2. EXISTS
3. FIRST, LAST
4. LIMIT
5. PRIOR, NEXT
-- PROCEDURES: 1. DELETE
2. EXTEND
3. TRIM

-- IN ORACLE PL/SQL, COLLECTION METHODS


CAN BE USED USING DOT(.) NOTATION

SYNTAX:
COLLECTION.METHOD(PARAMETERS)

1. COLLECTION METHOD COUNT:


-- COLLECTION METHOD COUNT()
RETURNS THE NUMBER OF ELEMENTS IN AN INITIALIZE COLLECTION
-- IF USED WITH AN INITIALIZE
COLLECTION WITH NO ELEMENTS IT RETURNS ZERO
-- IN CASE OF NESTED TABLE
COLLECTION METHOD, COUNT() ONLY RETURNS THE NUMBER OF EMPTY ELEMENTS
AS IT IS POSSIBLE FOR A
NESTED TABLE TO HAVE INDIVIDUAL ELEMENTS THAT ARE EMPTY

SQL> SET SERVEROUTPUT ON;


SQL> DECLARE
TYPE MY_NEST_TABLE IS TABLE OF NUMBER;
VAR_NT MY_NEST_TABLE :=
MY_NEST_TABLE(9, 18, 27, 36, 45, 54, 63, 72, 81, 90);
BEGIN
DBMS_OUTPUT.PUT_LINE('THE SIZE OF THE
NESTED TABLE IS '||VAR_NT.COUNT);
END;
/

SQL> SET SERVEROUTPUT ON;

SQL> DECLARE
TYPE MY_NEST_TABLE IS TABLE OF NUMBER;
VAR_NT MY_NEST_TABLE := MY_NEST_TABLE(9,
18, 27, 36, 45, 54, 63, 72, 81, 90);
BEGIN
IF VAR_NT.COUNT >= 10 THEN
DBMS_OUTPUT.PUT_LINE('YOU ARE ALREADY
INSERTED 10 ELEMENTS');
DBMS_OUTPUT.PUT_LINE('ARE YOU SURE YOU
WANT TO INSERT MORE?');
END IF;
END;
/

SQL> SET SERVEROUTPUT ON;

SQL> DECLARE
TYPE MY_NEST_TABLE IS TABLE OF NUMBER;
VAR_NT MY_NEST_TABLE := MY_NEST_TABLE(9,
18, 27, 36, 45, 54, 63, 72, 81, 90);
BEGIN
FOR I IN 1..VAR_NT.COUNT
LOOP
DBMS_OUTPUT.PUT_LINE('VALUE STORED AT
INDEX '||I||' IS '||VAR_NT(I));
END LOOP;
END;
/

2. COLLECTION METHOD EXISTS:


-- COLLECTION
METHOD EXISTS() CHECKS THE EXISTENCE OF AN ELEMENT AT A SPECIFIC INDEX IN A
COLLECTION
-- IF IT
FINDS THE SPECIFIED ELEMENT THEN IT RETURN TRUE OTHERWISE IT RETURNS FALSE

SQL> SET SERVEROUTPUT ON;

SQL> DECLARE
TYPE MY_NESTED_TABLE IS TABLE OF
VARCHAR2(20);
COL_VAR1 MY_NESTED_TABLE :=
MY_NESTED_TABLE('SUPERMAN', 'IRONMAN', 'BATMAN');
BEGIN
IF COL_VAR1.EXISTS(1) THEN
DBMS_OUTPUT.PUT_LINE('HEY! WE FOUND
'||COL_VAR1(1));
ELSE
DBMS_OUTPUT.PUT_LINE('SORRY! NO DATA
AT THIS INDEX');
END IF;
END;
/

SQL> SET SERVEROUTPUT ON;

SQL> DECLARE
TYPE MY_NESTED_TABLE IS TABLE OF
VARCHAR2(20);
COL_VAR1 MY_NESTED_TABLE :=
MY_NESTED_TABLE('SUPERMAN', 'IRONMAN', 'BATMAN');
BEGIN
IF COL_VAR1.EXISTS(4) THEN
DBMS_OUTPUT.PUT_LINE('HEY! WE FOUND
'||COL_VAR1(4));
ELSE
DBMS_OUTPUT.PUT_LINE('THIS INDEX IS
EMPTY. INSERTING NEW DATA....');
COL_VAR1.EXTEND;
COL_VAR1(4):= 'SPIDERMAN';
END IF;
DBMS_OUTPUT.PUT_LINE('NEW DATA AT
INDEX 4 IS '||COL_VAR1(4));
END;
/

3. COLLECTION METHOD FIRST AND


LAST:
-- WE USE
COLLECTION FUNCTIONS FIRST AND LAST TO KNOW THE FIRST AND LAST INDEX VALUES DEFINED

IN COLLECTION
--
YOU CAN USE BOTH THESE FUNCTIONS WITH ALL THREE TYPES OF COLLECTIONS
--
BOTH THE FUNCTIONS RETURN NULL WHEN APPLIED TO AN EMPTY COLLECTION
--
THEY RAISE COLLECTION_IS NULL EXCEPTION WHEN APPLIED TO AN UNINITIALIZED COLLECTION

SQL> SET SERVEROUTPUT ON;

SQL> DECLARE
TYPE NT_TAB IS TABLE OF NUMBER;
COL_VAR NT_TAB := NT_TAB(10, 20, 30,
40, 50);
BEGIN
DBMS_OUTPUT.PUT_LINE('FIRST INDEX OF
THE NESTED TABLE IS '||COL_VAR.FIRST);
DBMS_OUTPUT.PUT_LINE('LAST INDEX OF
THE NESTED TABLE IS '||COL_VAR.LAST);
END;
/

SQL> SET SERVEROUTPUT ON;

SQL> DECLARE
TYPE NT_TAB IS TABLE OF NUMBER;
COL_VAR NT_TAB := NT_TAB(10, 20, 30,
40, 50);
BEGIN
COL_VAR.DELETE(1);
DBMS_OUTPUT.PUT_LINE('FIRST INDEX OF
THE NESTED TABLE IS '||COL_VAR.FIRST);
END;
/

SQL> SET SERVEROUTPUT ON;

SQL> DECLARE
TYPE NT_TAB IS TABLE OF NUMBER;
COL_VAR NT_TAB := NT_TAB(10, 20, 30,
40, 50);
BEGIN
COL_VAR.TRIM;
DBMS_OUTPUT.PUT_LINE('LAST INDEX
AFTER TRIM '||COL_VAR.FIRST);
END;
/

SQL> SET SERVEROUTPUT ON;

SQL> DECLARE
TYPE NT_TAB IS TABLE OF NUMBER;
COL_VAR NT_TAB := NT_TAB(10, 20, 30,
40, 50);
BEGIN
COL_VAR.TRIM;
DBMS_OUTPUT.PUT_LINE('LAST INDEX AFTER
TRIM IS '||COL_VAR.LAST);
END;
/

4. COLLECTION METHOD LIMIT:

-- COLLECTION METHOD LIMIT


WHICH ACTUALLY A PL/SQL FUNCTION RETURNS THE MAXIMUM NUMBER OF ELEMENTS THAT
A
VARRAY CAN HOLD

SQL> SET SERVEROUTPUT ON;

SQL> DECLARE
TYPE INBLOCK_VRY IS VARRAY (5) OF
NUMBER;
VRY_OBJ INBLOCK_VRY :=
INBLOCK_VRY();
BEGIN
-- Let's find out total number of
indexes in the above VARRAY
DBMS_OUTPUT.PUT_LINE('TOTAL INDEXES
'||VRY_OBJ.LIMIT);
END;
/

SQL> SET SERVEROUTPUT ON;


SQL> DECLARE
TYPE INBLOCK_VRY IS VARRAY (5) OF
NUMBER;
VRY_OBJ INBLOCK_VRY :=
INBLOCK_VRY();
BEGIN
VRY_OBJ.EXTEND;
VRY_OBJ(1) := 10;
DBMS_OUTPUT.PUT_LINE('TOTAL INDEXES
'||VRY_OBJ.LIMIT);
DBMS_OUTPUT.PUT_LINE('RESULT OF
FUNCTION COUNT '||VRY_OBJ.COUNT);
END;
/

SQL> SET SERVEROUTPUT ON;

DECLARE
TYPE MY_NEST_TABLE IS TABLE OF
NUMBER;
VAR_NT MY_NEST_TABLE :=
MY_NEST_TABLE(9, 18, 27, 36, 45, 54, 63, 72, 81, 90);
BEGIN

DBMS_OUTPUT.PUT_LINE('RESULT OF LIMIT
'||VAR_NT.LIMIT);
DBMS_OUTPUT.PUT_LINE('RESULT OF COUNT
'||VAR_NT.COUNT);
END;
/

5. COLLECTION METHOD PRIOR AND


NEXT:
-- BOTH THESE FUNCTIONS TAKE AN
INDEX OF THE COLLECTION AS INPUT AND RETURN THE RESULT
--
PL/SQL COLLECTION MENTHOD PRIOR TAKES AN INDEX AS INPUT AND RETURN THE VALUE STORED
INTO THE PREVIOUS

LOWEST INDEX
-- THE
COLLECTION METHOD NEXT RETURNS THE VALUE FROM THE NEXT HIGHER INDEX

SQL> SET SERVEROUTPUT


ON;

SQL> DECLARE
TYPE MY_NEST_TABLE IS TABLE OF
NUMBER;
VAR_NT MY_NEST_TABLE :=
MY_NEST_TABLE(9, 18, 27, 36, 45, 54, 63, 72, 81, 90);
BEGIN
DBMS_OUTPUT.PUT_LINE('THE INDEX
BEFORE 3RD INDEX IS '||VAR_NT.PRIOR(3));
DBMS_OUTPUT.PUT_LINE('THE VALUE
BEFORE 3RD INDEX IS '||VAR_NT(VAR_NT.PRIOR(3)));
END;
/
SQL> SET SERVEROUTPUT ON;

SQL> DECLARE
TYPE MY_NEST_TABLE IS TABLE OF
NUMBER;
VAR_NT MY_NEST_TABLE :=
MY_NEST_TABLE(9, 18, 27, 36, 45, 54, 63, 72, 81, 90);
BEGIN
DBMS_OUTPUT.PUT_LINE('THE INDEX
BEFORE 3RD INDEX IS '||VAR_NT.NEXT(3));
DBMS_OUTPUT.PUT_LINE('THE VALUE
BEFORE 3RD INDEX IS '||VAR_NT(VAR_NT.NEXT(3)));
END;
/

6. COLLECTION METHOD DELETE:


-- REMOVES ELEMENTS FROM THE
COLLECTION
-- IS OVERLOADED PROCEDURE,
MEANS WE CAN USE SAME PROCEDURE IN THREE DIFFERENT WAYS
1. SIMPLE PROCEDURE CALL
WITHOUT ANY PARAMETER(IT WILL REMOVE ALL THE ELEMENTS FROM COLLECTION)
2. PROCEDURE CALL WITH
SINGLE PARAMETERS(REMOVE THE ELEMENT OF THE SPECIFIC INDEX)
3. PROCEDURE CALL WITH TWO
PARAMETERS(RANGE DELETE - REMOVES RANGE OF ELEMENTS IN START INDEX TO ENDING INDEX)

SQL> SET SERVEROUTPUT ON;

SQL> DECLARE
TYPE MY_NEST_TABLE IS TABLE OF
NUMBER;
VAR_NT MY_NEST_TABLE :=
MY_NEST_TABLE(9, 18, 27, 36, 45, 54, 63, 72, 81, 90);
BEGIN
DBMS_OUTPUT.PUT_LINE('VALUE AT
INDEX[5] BEFORE DELETE IS '||VAR_NT(5));
VAR_NT.DELETE(5);
DBMS_OUTPUT.PUT_LINE('VALUE AT
INDEX[5] AFRER DELETE IS '||VAR_NT(5));
END;
/

SQL> SET SERVEROUTPUT


ON;

SQL> DECLARE
TYPE MY_NEST_TABLE IS TABLE OF
NUMBER;
VAR_NT MY_NEST_TABLE :=
MY_NEST_TABLE(9, 18, 27, 36, 45, 54, 63, 72, 81, 90);
BEGIN
DBMS_OUTPUT.PUT_LINE('VALUE AT
INDEX[5] BEFORE DELETE IS '||VAR_NT(5));
VAR_NT.DELETE(5);
IF VAR_NT.EXISTS(5) THEN
DBMS_OUTPUT.PUT_LINE
('VALUE AT INDEX[5] AFTER DELETE IS '||VAR_NT(5));
ELSE
DBMS_OUTPUT.PUT_LINE('DATA
NOT FOUND');
END IF;
END;
/

SQL> SET SERVEROUTPUT


ON;

SQL> DECLARE
TYPE MY_NEST_TABLE IS TABLE OF
NUMBER;
VAR_NT MY_NEST_TABLE :=
MY_NEST_TABLE(9, 18, 27, 36, 45, 54, 63, 72, 81, 90);
BEGIN
VAR_NT.DELETE(2, 6);
FOR I IN 1..VAR_NT.LAST
LOOP
IF VAR_NT.EXISTS(I) THEN
DBMS_OUTPUT.PUT_LINE('VALUE
AT INDEX ['||I||'] IS '||VAR_NT(I));
END IF;
END LOOP;
END;
/

7. COLLECTION METHOD EXTEND:


-- OVERLOADED
PL/SQL PROCEDURE WHICH IS USED FOR APPENDING ELEMENTS TO THE COLLECTION
-- CAN BE
CALLED IN 3 WAYS
1. CALL
WITHOUT ANY ARGUMENT(WILL APPEND SINGLE ELEMENT)
2. CALL
WITH SINGLE ARGUMENT(WILL APPEND NUMBER OF NULL ELEMENTS THAT YOU MENTIONED IN
ARGUMENT AND MUST BE A INTEGER VALUE)
3. CALL
WITH TWO ARGUMENTS(FIRST ARGUMENT INDICATES NUMBER OF ELEMENTS, SECOND ARGUMENT IS
INDEX NUMBER)
-- CAN ONLY
USED WITH PL/SQL COLLECTIONS NESTED TABLE AND VARRAY
-- WE CANNOT BE USED WITH THE
ASSOCIATIVE ARRAY

SQL> SET SERVEROUTPUT ON;

SQL> DECLARE
TYPE MY_NEST_TABLE IS TABLE OF
NUMBER;
NT_OBJ MY_NEST_TABLE :=
MY_NEST_TABLE();
BEGIN
NT_OBJ(1) := 10;
DBMS_OUTPUT.PUT_LINE('DATA AT
INDEX 1 IS '||NT_OBJ(1));
END;
/

SQL> SET SERVEROUTPUT


ON;

SQL> DECLARE
TYPE MY_NEST_TABLE IS TABLE OF
NUMBER;
NT_OBJ MY_NEST_TABLE :=
MY_NEST_TABLE();
BEGIN
NT_OBJ.EXTEND;
NT_OBJ(1) := 10;
DBMS_OUTPUT.PUT_LINE('DATA AT
INDEX 1 IS '||NT_OBJ(1));
END;
/

SQL> DECLARE
TYPE MY_NEST_TABLE IS TABLE OF
NUMBER;
NT_OBJ MY_NEST_TABLE :=
MY_NEST_TABLE();
BEGIN
NT_OBJ.EXTEND(3);
NT_OBJ(1) := 10;
NT_OBJ(2) := 20;
NT_OBJ(3) := 30;
DBMS_OUTPUT.PUT_LINE('DATA AT
INDEX 1 IS '||NT_OBJ(1));
DBMS_OUTPUT.PUT_LINE('DATA AT
INDEX 1 IS '||NT_OBJ(2));
DBMS_OUTPUT.PUT_LINE('DATA AT
INDEX 1 IS '||NT_OBJ(3));
END;
/

SQL> DECLARE
TYPE MY_NEST_TABLE IS TABLE OF
NUMBER;
NT_OBJ MY_NEST_TABLE :=
MY_NEST_TABLE();
BEGIN
NT_OBJ.EXTEND;
NT_OBJ(1) := 10;
DBMS_OUTPUT.PUT_LINE('DATA AT
INDEX 1 IS '||NT_OBJ(1));
NT_OBJ.EXTEND(5, 1);
DBMS_OUTPUT.PUT_LINE('DATA AT
INDEX 4 IS '||NT_OBJ(1));

END;
/

8. COLLECTION METHOD TRIM:


-- IS AN
OVERLOADED PROCEDURE USING WHICH YOU CAN REMOVE ONE OR MORE ELEMENTS FROM THE END
OF THE COLLECTION
-- CAN
CALL IT BY 2 WAYS
1.
WITHOUT ANY PARAMETER(REMOVE ONLY ONE ELEMENT FROM THE END OF THAT COLLECTION)
2.
WITH ONE PARAMETER(REMOVE NO. OF ELEMENTS THAT SPECIFIED BY THE PARAMETER

SQL> SET SERVEROUTPUT


ON;

SQL> DECLARE
TYPE MY_NEST_TABLE IS TABLE OF
NUMBER;
NT_OBJ MY_NEST_TABLE :=
MY_NEST_TABLE(1, 2, 3, 4, 5);
BEGIN
NT_OBJ.TRIM;

DBMS_OUTPUT.PUT_LINE('AFTER TRIM PROCEDURE CALL');


FOR I IN 1..NT_OBJ.COUNT
LOOP

DBMS_OUTPUT.PUT_LINE(NT_OBJ(I));
END LOOP;
END;
/

SQL> DECLARE
TYPE MY_NEST_TABLE IS TABLE OF
NUMBER;
NT_OBJ MY_NEST_TABLE :=
MY_NEST_TABLE(1, 2, 3, 4, 5);
BEGIN
NT_OBJ.TRIM(2);
DBMS_OUTPUT.PUT_LINE('AFTER TRIM
PROCEDURE CALL');
FOR I IN 1..NT_OBJ.COUNT
LOOP

DBMS_OUTPUT.PUT_LINE(NT_OBJ(I));
END LOOP;
END;
/

REF CURSORS IN PL/SQL:


-- IT IS PL/SQL DATATYPE USING WHICH
YOU CAN DECLARE A SPECIAL TYPE OF VARIABLE CALLED CURSOR VARIABLE
-- A SINGLE CURSOR VARIABLE CAN BE
ASSOCIATED WITH MULTIPLE SELECT STATEMENTS IN A SINGLE PL/SQL BLOCK
-- A STATIC CURSOR CAN ONLY ACCESS
SINGLE SELECT STATEMENT AT A TIME

TYPES OF REF CURSORS:


1. STRONG REF CURSORS
2. WEAK REF CURSORS

1. STRONG REF CURSORS: -- ANY REF CURSOR WHICH


HAS FIXED RETURN TYPE IS CALLED STRONG REF CURSOR
--
WHEREAS STRONG REF CURSORS CAN ONLY BE USED WITH THOSE SELECT STATEMENTS THAT
RETURN THE RESULT

SYNTAX: DECLARE
TYPE REF_CURSOR_NAME IS REF
CURSOR
RETURN(RETURN TYPE);
--- RETURN TYPE MUST ALWAYS
ONLY RECORD TYPE

2. WEAK REF CURSORS: -- THOSE REF CURSORS WHICH


DO NOT HAVE FIXED RETURN TYPE ARE CALLED WEAK REF CURSORS
-- SUCH REF CURSORS ARE
MOST FREQUENTLY USED REF CURSORS AS THEY ARE OPEN TO ALL SELECT STATEMENTS

SYNTAX: DECLARE
TYPE REF_CURSOR_NAME IS REF
CURSOR;

3. SYS_REFCURSOR: -- IS AN ORACLE BUILT IN


CURSOR VARIABLE
-- IT DECLARE A WEAK REF
CURSOR AND THAT TOO WITHOUT DECLARING THE REF POINTER TYPE
--
IS A PREDEFINED WEAK REF CURSOR WHICH COMES BUILT IN WITH THE ORACLE DATABASE
SOFTWARE

1. STRONG REF CURSOR:

SQL> SET SERVEROUTPUT ON;

SQL> DECLARE
TYPE MY_REFCUR IS REF CURSOR
RETURN EMPLOYEES%ROWTYPE;
CUR_VAR MY_REFCUR;
REC_VAR EMPLOYEES%ROWTYPE;
BEGIN
OPEN CUR_VAR FOR SELECT * FROM
EMPLOYEES WHERE EMPLOYEE_ID = 100;
FETCH CUR_VAR INTO REC_VAR;
CLOSE CUR_VAR;
DBMS_OUTPUT.PUT_LINE('EMPLOYEE
'||REC_VAR.FIRST_NAME||' HAS SALARY '||REC_VAR.SALARY);
END;
/

SQL> DECLARE
TYPE MY_REC IS RECORD
(
EMP_SAL EMPLOYEES.SALARY%TYPE
);
TYPE REFCUR IS REF CURSOR
RETURN MY_REC;
CUR_VAR REFCUR;
AT_VAR EMPLOYEES.SALARY%TYPE;
BEGIN
OPEN CUR_VAR FOR SELECT SALARY
FROM EMPLOYEES WHERE EMPLOYEE_ID = 100;
FETCH CUR_VAR INTO AT_VAR;
CLOSE CUR_VAR;
DBMS_OUTPUT.PUT_LINE('SALARY
OF THE EMPLOYEE IS '||AT_VAR);
END;
/

2. WEAK REF CURSOR:

SQL> SET SERVEROUTPUT ON;

SQL> DECLARE
TYPE WK_REFCUR IS REF CURSOR;
CUR_VAR WK_REFCUR;
F_NAME EMPLOYEES.FIRST_NAME
%TYPE;
EMP_SAL EMPLOYEES.SALARY%TYPE;
BEGIN
OPEN CUR_VAR FOR SELECT
FIRST_NAME, SALARY FROM EMPLOYEES WHERE EMPLOYEE_ID = 100;
FETCH CUR_VAR INTO F_NAME,
EMP_SAL;
CLOSE CUR_VAR;
DBMS_OUTPUT.PUT_LINE(F_NAME||'
'||EMP_SAL);
END;
/

3. SYS REF CURSOR:

SQL> SET SERVEROUTPUT ON;

SQL> DECLARE
CUR_VAR SYS_REFCURSOR;
F_NAME EMPLOYEES.FIRST_NAME
%TYPE;
EMP_SAL EMPLOYEES.SALARY%TYPE;
BEGIN
OPEN CUR_VAR FOR SELECT
FIRST_NAME, SALARY FROM EMPLOYEES WHERE EMPLOYEE_ID = 100;
FETCH CUR_VAR INTO F_NAME,
EMP_SAL;
CLOSE CUR_VAR;
DBMS_OUTPUT.PUT_LINE(F_NAME||'
'||EMP_SAL);
END;
/

BULK COLLECT CLAUSE IN ORACLE DB:


-- REDUCING CONTEXT SWITCHING AND
IMPROVING PERFORMANCE
-- REDUCES MULTIPLE CONTROL
HOPING BY COLLECTING ALL THE SQL STATEMENT CALL FROM PL/SQL PROGRAM
AND SENDING THEM TO SQL ENGINE
IN JUST ONE GO
-- BULK COLLECT CLAUSE
REDUCES/COMPRESSES MULTIPLE SWITCHES INTO A SINGLE CONTEXT SWITCH
-- THE PROCESS OF FETCHING
BATCHES OF DATA FROM PL/SQL RUNTIME ENGINE TO SQL RUNTIME ENGINE AND
VICE-
VERSA IS CALLED BULK DATA PROCESSING
-- CAN BE
USED WITH

1. SELECT-INTO
2. FETCH-INTO
3. RETURNING-
INTO

1. BULK COLLECT WITH SELECT-INTO:

SQL> SET SERVEROUTPUT ON;

SQL> DECLARE
TYPE NT_FNAME IS TABLE OF
VARCHAR2(20); ---PLS-00642: local collection types not allowed in SQL statements
FNAME NT_FNAME;
BEGIN
SELECT FIRST_NAME INTO FNAME FROM
EMPLOYEES;
END;
/

SQL> DECLARE
TYPE NT_FNAME IS TABLE OF
VARCHAR2(20);
FNAME NT_FNAME;
BEGIN
SELECT FIRST_NAME BULK COLLECT
INTO FNAME FROM EMPLOYEES;
FOR I IN 1..FNAME.COUNT
LOOP
DBMS_OUTPUT.PUT_LINE(I||' - '||
FNAME(I));
END LOOP;
END;
/

2. BULCK COLLECT WITH FETCH-INTO:

SQL> SET SERVEROUTPUT ON;

SQL> DECLARE
CURSOR EXP_CUR IS
SELECT FIRST_NAME FROM
EMPLOYEES;

TYPE NT_FNAME IS TABLE OF


VARCHAR2(20);
FNAME NT_FNAME;
BEGIN
OPEN EXP_CUR;
LOOP
FETCH EXP_CUR BULK COLLECT
INTO FNAME;
EXIT WHEN FNAME.COUNT = 0;
FOR I IN
FNAME.FIRST..FNAME.LAST
LOOP
DBMS_OUTPUT.PUT_LINE(I||' -
'||FNAME(I));
END LOOP;
END LOOP;
CLOSE EXP_CUR;
END;
/

3. BULK COLLECT WITH LIMIT:

-- MEMORY OVERHEAD DUE


TO BULK COLLECT - WHENEVER WE RETRIEVE OR FETCH A LARGE NUMBER OF RECORDS USING
BULK COLLECT
OUR PROGRAM STARTS CONSUMING A LOT OF
MEMORY IN ORDER TO BE FAST AND EFFICIENT THAT DEGRADES PERFORMANCE

SQL> SET SERVEROUTPUT ON;

SQL> DECLARE
CURSOR EXP_CUR IS
SELECT FIRST_NAME FROM
EMPLOYEES;

TYPE NT_FNAME IS TABLE OF


VARCHAR2(20);
FNAME NT_FNAME;
BEGIN
OPEN EXP_CUR;
FETCH EXP_CUR BULK COLLECT INTO
FNAME LIMIT 10;
FOR I IN FNAME.FIRST..FNAME.LAST
LOOP
DBMS_OUTPUT.PUT_LINE(I||' -
'||FNAME(I));
END LOOP;
CLOSE EXP_CUR;
END;
/

FORALL STATEMENT IN PL/SQL:

-- FORALL STATEMENT REDUCES


CONTEXT SWITCHES WHICH OCCUR DURING THE EXECUTION OF A DML STATEMENT IN A LOOP
-- FORALL IS BULK LOOP
CONSTRUCT WHICH EXECUTES ONE DML STATEMENT MULTIPLE TIMES AT ONCE
-- FORALL STATEMENT
REDUCES CONTEXT SWITCHES BY SENDING EXECUTION CALL OF DML FROM PL/SQL TO SQL IN
BATCHES
INSTEAD OF ONE AT A
TIME

SYNTAX: FORALL INDEX IN


BOUND_CLAUSE
[SAVE EXCEPTION]
DML
STATEMENT;
-- BOUND CLAUSE =
CONTROLS THE VALUE OF INDEX AS WELL AS DECIDES THE NUMBER OF ITERATION OF FORALL
STATEMENT

1. LOWER AND UPPER BOUND


CLAUSE:

SQL> SET SERVEROUTPUT


ON;

SQL> CREATE TABLE TUT_77


(
MUL_TAB NUMBER
);

SQL> DECLARE
TYPE MY_ARRAY IS TABLE OF NUMBER
INDEX BY PLS_INTEGER;
COL_VAR MY_ARRAY;
TOT_REC NUMBER;
BEGIN
--POPULATE THE COLLECTION
FOR I IN 1..10 LOOP
COL_VAR(I):=9*I;
END LOOP;

FORALL IDX IN 1..10


INSERT INTO TUT_77(MUL_TAB)
VALUES(COL_VAR(IDX));

SELECT COUNT(*) INTO TOT_REC


FROM TUT_77;
DBMS_OUTPUT.PUT_LINE('TOTAL
RECORDS INSERTED ARE '||TOT_REC);
END;
/
2. INDECES OF CLAUSE:

SQL> SET SERVEROUTPUT


ON;

SQL> CREATE TABLE TUT_78


(
MUL_TAB NUMBER
);

SQL> DECLARE
TYPE MY_NEST_TABLE IS TABLE OF
NUMBER;
VAR_NT MY_NEST_TABLE :=
MY_NEST_TABLE(9, 18, 27, 36, 45, 54, 63, 72, 81, 90);
BEGIN
VAR_NT.DELETE(3, 6);
FOR I IN 1..VAR_NT.LAST
LOOP
IF VAR_NT.EXISTS(I) THEN

DBMS_OUTPUT.PUT_LINE(VAR_NT(I));
ELSE
DBMS_OUTPUT.PUT_LINE('NO
DATA AT INDEX NUMBER '||I);
END IF;
END LOOP;
END;
/

SQL> SET SERVEROUTPUT ON;

SQL> DECLARE
TYPE MY_NEST_TABLE IS TABLE OF
NUMBER;
VAR_NT MY_NEST_TABLE :=
MY_NEST_TABLE(9, 18, 27, 36, 45, 54, 63, 72, 81, 90);
BEGIN
VAR_NT.DELETE(3, 6);
FORALL IDX IN 1..10
INSERT INTO TUT_78
VALUES(VAR_NT(IDX));
END;
/

SQL> SET SERVEROUTPUT ON;

SQL> DECLARE
TYPE MY_NEST_TABLE IS TABLE OF
NUMBER;
VAR_NT MY_NEST_TABLE :=
MY_NEST_TABLE(9, 18, 27, 36, 45, 54, 63, 72, 81, 90);
TOT_REC NUMBER;
BEGIN
VAR_NT.DELETE(3, 6);
FORALL IDX IN INDICES OF VAR_NT
INSERT INTO TUT_78
(MUL_TAB) VALUES(VAR_NT (IDX));

SELECT COUNT(*) INTO


TOT_REC FROM TUT_78;

DBMS_OUTPUT.PUT_LINE('TOTAL RECORDS INSERTED ARE '||TOT_REC);


END;
/

3. VALUES OF CLAUSE:

SQL> SET SERVEROUTPUT ON;

SQL> CREATE TABLE TUT_79


(
SELECTED_DATA
NUMBER(4);
);

SQL> DECLARE
TYPE
MY_NEST_TABLE ISS TABLE OF NUMBER;
SOURCE_COL MY_NEST_TABLE := MY_NEST_TABLE(9, 18, 27, 36, 45, 54, 63, 72, 81,
90);

TYPE
MY_ARRAY IS TABLE OF PLS_INTEGER INDEX BY PLS_INTEGER

INDEX_COL MY_ARRAY;
BEGIN
INDEX_COL(1) := 3
INDEX_COL(5) := 7
INDEX_COL(12):= 8
INDEX_COL(28):=10
FORALL IDX IN VALUES OF INDEX_COL

INSERT INTO TUT_79


VALUES(SOURCE_COL(IDX));
END;
/

NATIVE DYNAMIC SQL IN PL/SQL:


-- STATIC SQL: ANY SQL STATEMENT WHICH DOES
NOT CHANGE DURING THE RUNTIME AND REMAINS FIXED IS CALLED STATIC SQL STATEMENT
-- ADVANTAGE IS ALL THE DEPENDED OBJECTS
OVER WHICH WE ARE WRITING THE STATEMENT ARE PRESENT OR NOT
-- BBIGGEST ADVANTAGE OF STATIC SQL
STATEMENT IS THAT WE HARDCODE THESE STATEMENTS INTO OUT APPLICATION THUS WE CAN
TUNE THEM
FOR OPTIMAL PERFORMANCE

DYNAMIC SQL: -- ANY SQL STATEMENT IS CONSTRUCTED AT


RUNTIME IS CALLED DYNAMIC SQL
-- AS THESE STATEMENTS ARE
BUILT ON THE FLY THUS THEY CANNOT BE HARDCODED INTO APPLICATION WHICH IN TURN
INCREASES THE FLEXIBILITY
-- STATIC SQL EXECUTES
ONLY DML STATEMENTS IN PL/SQL BLOCK, A DYNAMIC SQL ENABLES TO EXECUTES DDL
STATEMENTS INSIDE PL/SQL BLOCK

DYNAMIC PL/SQL: PROCESS OF CONSTRUCTING PL/SQL CODE AT


RUNTIME IS CALLED DYNAMIC PL/SQL

USE OF DYNAMIC SQL: 1. EXECUTE IMMEDIATE STATEMENT


2. OPEN-FOR, FETCH, CLOSE BLOCK

METHODS: 1. BULK FETCH


2. BULK EXECUTE IMMEDIATE
3. BULK FORALL
4. BULK COLLECT INTO STATEMENT

1. EXECUTE IMMEDIATE WITH INTO CLAUSE


-- USING EXECUTE IMMEDIATE WE
CAN PARSE AND EXECUTE ANY SQL STATEMENT OR A PL/SQL BLOCK DYNAMICALLY IN ORACLE
DATABASE
-- EXECUTE IMMEDIATE IS BEST
SUITED FOR THOSE SQL STATEMENTS WHICH RETURN A SINGLE ROW OF RESULTS

SYNTAX: EXECUTE IMMEDIATE DYNAMIC_QUERY


[INTO USER_DEFINED_VARIABLE-1,
USER_DEFINED_VARIABLE-2..]
[USING BIND_ARGUMENT-1,
BIND_ARGUMENT-2..]
[RETURNING | RETURN-INTO CLAUSE];

SQL> SET SERVEROUTPUT ON;

SQL> DECLARE
SQL_QRY VARCHAR2(150);
EMP_TOT NUMBER(3);
BEGIN
SQL_QRY := 'SELECT COUNT(*) FROM
EMPLOYEES';
EXECUTE IMMEDIATE SQL_QRY INTO
EMP_TOT;
DBMS_OUTPUT.PUT_LINE('TOTAL
EMPLOYEES ARE '||EMP_TOT);
END;
/

SQL> SET SERVEROUTPUT ON;

SQL> BEGIN
CREATE TABLE TUT_81
(
TUT_NUM NUMBER(3),
--PLS-00103: Encountered the symbol "CREATE" when expecting one of the following:
TUT_NAME VARCHAR2(50)
);
END;
/

SQL> SET SERVEROUTPUT


ON;

SQL> DECLARE
DDL_QRY VARCHAR2(150);
BEGIN
DDL_QRY := 'CREATE TABLE TUT_82
(
TUT_NUM NUMBER(3),

TUT_NAME VARCHAR2(50)
)';
EXECUTE IMMEDIATE DDL_QRY;
END;
/

SQL> SET SERVEROUTPUT ON;

SQL> DECLARE
DDL_QRY VARCHAR2(150);
BEGIN
DDL_QRY := 'CREATE TABLE
TUT_83'||
'('||
'TUT_NUM
NUMBER(5),'||
'TUT_NAME
VARCHAR2(50),'||
'CONSTRAINT TUT_PK
PRIMARY KEY(TUT_NUM)'||
')';
EXECUTE IMMEDIATE DDL_QRY;
END;
/

SQL> SET SERVEROUTPUT


ON;

SQL> DECLARE
DDL_QRY VARCHAR2(50);
BEGIN
DDL_QRY := 'ALTER TABLE TUT_83
ADD TUT_DATE DATE';
EXECUTE IMMEDIATE DDL_QRY;
END;
/

SQL> SET SERVEROUTPUT


ON;
SQL> DECLARE
SQL_SMT VARCHAR2(150);
BEGIN
SQL_SMT := 'INSERT INTO
STU_INFO(STUDENT_NAME) VALUES (:STU_NAME)'; --ORA-01008: not all variables bound
EXECUTE IMMEDIATE SQL_SMT;
END;
/

SQL> SET SERVEROUTPUT


ON;

SQL> DECLARE
SQL_SMT VARCHAR2(150);
BEGIN
SQL_SMT := 'UPDATE STU_INFO SET
STUDENT_NAME = :NEW_NAME
WHERE STUDENT_NAME
= :OLD_NAME';
EXECUTE IMMEDIATE SQL_SMT USING
'SURESH', 'LEO';
END;
/

SQL> SET SERVEROUTPUT


ON;

SQL> DECLARE
SQL_SMT VARCHAR2(150);
BEGIN
SQL_SMT := 'UPDATE STU_INFO SET
STUDENT_NAME = :NEW_NAME
WHERE STUDENT_NAME
= :OLD_NAME';
EXECUTE IMMEDIATE SQL_SMT USING
'SURESH'; --ORA-01008: not all variables bound
END;
/
SQL> SET SERVEROUTPUT
ON;

SQL> DECLARE
SQL_SMT VARCHAR2(150);
BEGIN
SQL_SMT := 'UPDATE :TABLE_NAME
SET STUDENT_NAME = :NEW_NAME
WHERE STUDENT_NAME
= :OLD_NAME';
EXECUTE IMMEDIATE SQL_SMT USING
'STU_INFO','SUDHAKAR', 'SURESH'; ---ORA-00903: invalid table name
END;
/

SQL> SET SERVEROUTPUT


ON;

SQL> DECLARE
TYPE NT_FNAME IS TABLE OF
VARCHAR2(60);
FNAME NT_FNAME;
SQL_QRY VARCHAR2(150);
BEGIN
SQL_QRY := 'SELECT FIRST_NAME
BULK COLLECT INTO FNAME FROM EMPLOYEES'; --ORA-03001: unimplemented feature
EXECUTE IMMEDIATE SQL_QRY;
END;
/

SQL> SET SERVEROUTPUT ON;

SQL> DECLARE
TYPE NT_FNAME IS TABLE OF
VARCHAR2(60);
FNAME NT_FNAME;
SQL_QRY VARCHAR2(150);
SQL> BEGIN
SQL_QRY := 'SELECT FIRST_NAME
FROM EMPLOYEES';
EXECUTE IMMEDIATE SQL_QRY BULK
COLLECT INTO FNAME;
FOR I IN 1..FNAME.LAST
LOOP
DBMS_OUTPUT.PUT_LINE(I||' - '||
FNAME(I));
END LOOP;
END;
/

SQL> SET SERVEROUTPUT


ON;

SQL> DECLARE
PL_BLK VARCHAR2(250);
BEGIN
PL_BLK := 'DECLARE
VAR_USER
VARCHAR2(10);
BEGIN
SELECT USER INTO
VAR_USER FROM DUAL;

DBMS_OUTPUT.PUT_LINE(''CURRENT USER IS ''||VAR_USER);


END;';
EXECUTE IMMEDIATE PL_BLK;
END;
/

Das könnte Ihnen auch gefallen