You are on page 1of 0

Advanced Oracle PLSQL

programming
Advantech 1 Krishnamurthy
Anonymous Procedure Function
[DECLARE]
BEGIN
--statements
[EXCEPTION]
END;
PROCEDURE name
IS
BEGIN
--statements
[EXCEPTION]
END;
FUNCTION name
RETURN datatype
IS
BEGIN
--statements
RETURN value;
[EXCEPTION]
END;
PL/SQL Block Structure
Advantech 2 Krishnamurthy
Naming Conventions
Advantages of proper naming
conventions:
Easier to read
Understandable
Gives information about the functionality
Easier to debug
Ensures consistency
Advantech 3 Krishnamurthy
Do not use reserved keywords as identifiers:
To list reserved keywords use data dictionary view v$reserved_words
- select keyword from v$reserved_words;
Label blocks You can give a name to a block so that you can
access corresponding blocks variables in sub-blocks
Loop Labels - You can give a name to a loop by using a label
<<year_loop>>
FOR year_number IN 1800..1995
LOOP
<<month_loop>>
FOR month_number IN 1 .. 12
LOOP
IF year_loop.year_number = 1900 THEN ... END IF;
END LOOP month_loop;
END LOOP year_loop;
Advantech 4 Krishnamurthy
Procedures
A procedure is:
A named PL/SQL block that performs a
sequence of actions and optionally returns a
value or values
Stored in the database as a schema object
Used to promote reusability and
maintainability
[CREATE [OR REPLACE]] PROCEDURE [schema.]name
[( parameter [, parameter ...] ) ]
[AUTHID DEFINER | CURRENT_USER] IS
[declarations]
[PRAGMA AUTONOMOUS_TRANSACTION]
BEGIN executable statements
[ EXCEPTION exception handlers]
END [name];
Note : Importance of OR REPLACE to be explained
Advantech 5 Krishnamurthy
Procedural Parameter Modes
Calling
environment
Procedure
procedure
BEGIN
EXCEPTION
END;
IN parameter
OUT parameter
IN OUT parameter
Advantech 6 Krishnamurthy
Any assignments made to
parameters are rolled
back when an exception
is raised in the program*
Any assignments made
to parameters are rolled
back when an exception
is raised in the program*
In parameter
cannot be
modified in the
program*
Actual parameter must be
a variable
Actual parameter must
be a variable
Actual parameter
can be constant,
expression,
variable etc.,
Cannot have default
value
Cannot have default
value
Can have default
value
Sub-program takes
in/gives out value
Sub-program gives out
value
Sub-program
takes value
Pass by value Pass by value Pass by reference
IN OUT OUT IN
Parameter modes
*example discussed in next slide
Advantech 7 Krishnamurthy
IN parameter
-variable vsal number
-exec :vsal:=1000
-create or replace procedure ex(psal IN number)
is
begin
psal:=500; -- illegal
update . . .
end;
/
OUT / IN OUT parameter
-variable vsal number
-create or replace procedure ex(psal OUT number)
is
begin
psal:=500; -- rolled back
select sal into psal from emp where empno=9999; -- raises excep.
end;
/
-exec ex(:vsal)
-print vsal
(null)
Advantech 8 Krishnamurthy
The NOCOPY Parameter Mode Hint
NOCOPY is a hint to the compiler about how you would like the
PL/SQL engine to work with the data structure being passed in as an
OUT or IN OUT parameter.
Parameter mode Passed by value or reference? (default)
IN By reference
OUT By value
IN OUT By value
We can infer from these definitions and rules that when a large data
structure (such as a collection, a record, or an instance of an object
type) is passed as an OUT or IN OUT parameter, that structure will
be passed by value, and your application could experience
performance and memory degradation as a result of all this copying.
The NOCOPY hint is a way for you to attempt to avoid this.
The syntax of this feature is as follows:
parameter_name OUT NOCOPY or IN OUT NOCOPY datatype
Advantech 9 Krishnamurthy
Matching Actual and Formal Parameters in PL/SQL
PL/SQL offers two ways to make the association between actual and
formal parameters:
Positional notation - Associate the actual parameter implicitly (by
position) with the formal parameter.
Named notation - Associate the actual parameter explicitly (by
name) with the formal parameter.
It is more efficient to use this named notation method since it is self-
explanatory (what data to which parameter etc.,)
You can also include only the parameters you want or need in the
parameter list.
Advantech 10 Krishnamurthy
AUTHID [DEFINER] | CURRENT_USER
CREATE OR REPLACE PROCEDURE remove_emp(
p_empno IN emp.empno%type,
p_ename OUT emp.ename%type)
AUTHID CURRENT_USER
IS
BEGIN
DELETE EMP WHERE EMPNO=p_empno
RETURNING ename INTO p_ename;
IF SQL%FOUND THEN
dbms_output.put_line(sql%rowcount||' row deleted.');
COMMIT;
ELSE
dbms_output.put_line('0 rows deleted.');
END IF;
END;
Advantech 11 Krishnamurthy
PRAGMA AUTONOMOUS_TRANSACTION
These are independent transactions which performs commit/rollback
only local DML changes and not main transaction. These are started
and ended by named subprograms
CREATE OR REPLACE PROCEDURE ADD_PLAYER(name VARCHAR2)
IS
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
INSERT INTO CRICKET VALUES(NAME);
COMMIT; -- tcl command mandatory else throws runtime errors
END;
/
INSERT INTO CRICKET VALUES('DRAVID');
EXEC ADD_PLAYER('SEHWAG'); -- COMMITTED
ROLLBACK; -- rolls back inserting of DRAVID record but SEHWAG is
added and committed
Advantech 12 Krishnamurthy
Functions
A function is:
A named block that must return a value
Stored in the database as a schema object
Called as part of an expression or used to
provide a parameter value
[CREATE [OR REPLACE]] FUNCTION [schema.]name
[( parameter [, parameter ...] ) ]
RETURN return_datatype
[AUTHID DEFINER | CURRENT_USER]
[DETERMINISTIC] [PARALLEL ENABLE ...] [PIPELINED]
[RESULT_CACHE [RELIES ON table_name]]
IS [declaration statements]
BEGIN executable statements
[EXCEPTION exception handler statements]
END [ name ];
Advantech 13 Krishnamurthy
Function: Example
CREATE OR REPLACE FUNCTION get_maxsal_limit(
p_empno IN emp.empno%type)
RETURN number
is
v_hisal salgrade.hisal%type;
BEGIN
SELECT hisal INTO v_hisal
FROM salgrade s,emp e
WHERE sal between losal and hisal
and e.empno=p_empno;
RETURN v_hisal;
EXCEPTION
WHEN others THEN
RETURN null;
END;
/
exec dbms_output.put_line(get_maxsal_limit(7566));
Advantech 14 Krishnamurthy
Ways to Execute Functions
Invoke as part of a PL/SQL expression
Using a host variable to obtain the result:
Using a local variable to obtain the result:
Use as a parameter to another subprogram
Use in a SQL statement (subject to restrictions)
EXECUTE dbms_output.put_line(get_maxsal_limit(7566))
select empno,ename,sal,get_maxsal_limit(empno) from emp;
VARIABLE v_hisal NUMBER
EXECUTE :v_hisal := get_maxsal_limit(7566)
DECLARE v_hisal salgrade.hisal%type;
BEGIN
v_hisal := get_maxsal_limit(7566); ...
END;
Advantech 15 Krishnamurthy
Restrictions on Calling Functions
from SQL Expressions
User-defined functions that are callable from
SQL expressions must:
Be stored in the database
Accept only I Nparameters with valid SQL data types,
not PL/SQL-specific types
Return valid SQL data types, not PL/SQL-specific
types
When calling functions in SQL statements:
Parameters must be specified with positional notation
You must own the function or have the EXECUTE
privilege
Advantech 16 Krishnamurthy
Restrictions on Calling Functions
from SQL Expressions
Functions called from:
A SELECT statement cannot contain DML statements
An UPDATE or DELETE statement on a table T cannot query or
contain DML on the same table T
SQL statements cannot end transactions (that is, cannot
execute COMMI T or ROLLBACK operations)
Note: Calls to subprograms that break these restrictions
are also not allowed in the function.
Advantech 17 Krishnamurthy
You cannot have DML in a function which are invoked using
select statement
create or replace function del_emp(e number)
return number
is
n number;
begin
delete emp where empno=e;
n:=sql%rowcount;
return n;
end;
/
SQL> select del_emp(7566) from dual;
select del_emp(7566) from dual
*
ERROR at line 1:
ORA-14551: cannot perform a DML operation inside a query
Advantech 18 Krishnamurthy
PL/SQL Packages: Review
PL/SQL packages:
Group logically related components:
PL/SQL types
Variables, data structures, and exceptions
Subprograms: procedures and functions
Consist of two parts:
A specification
A body
Enable the Oracle server to read multiple objects
into memory simultaneously
Advantech 19 Krishnamurthy
Components of a PL/SQL Package
Package
specification
Package
body
Procedure A declaration;
variable
Procedure A definition
BEGIN

END;
Procedure B definition
variable
variable
Public
Private
Advantech 20 Krishnamurthy
Creating the Package Specification
Syntax:
The OR REPLACE option drops and re-creates the package
specification.
Variables declared in the package specification are initialized
to NULL by default.
All constructs declared in a package specification are visible
to users who are granted privileges on the package.
CREATE [OR REPLACE] PACKAGE package_name IS|AS
public type and variable declarations
subprogram specifications
END [package_name];
Advantech 21 Krishnamurthy
Creating the Package Body
Syntax:
The OR REPLACE option drops and re-creates the package
body.
Identifiers defined in the package body are private and not
visible outside the package body.
All private constructs must be declared before they are
referenced.
Public constructs are visible to the package body.
CREATE [OR REPLACE] PACKAGE BODY package_name IS|AS
private type and variable declarations
subprogram bodies
[BEGIN initialization statements]
END [package_name];
Advantech 22 Krishnamurthy
CURSORs
Whenever you issue a SQL statement, the Oracle
server opens an area of memory in which the
command is parsed and executed. This area is
called a cursor.
Types of cursor's
1.IMPLICIT cursor
-automatically defined by oracle
-INSERT/UPDATE/DELETE
-SELECT INTO statement which returns single row
-Name: SQL
2.EXPLICIT cursor
-user defined cursors
-SELECT statement which returns zero or more rows
-Name: user-defined cursor name
Advantech 23 Krishnamurthy
CURSORs
Advantech 24 Krishnamurthy
Controlling Explicit Cursors
Controlling Explicit Cursors
Create a
named
SQL area
DECLARE DECLARE
Identify
the active
set
OPEN OPEN
Load the
current
row into
variables
FETCH FETCH
Release
the active
set
CLOSE CLOSE
Yes
Test for
existing
rows
EMPTY? EMPTY?
Return to
FETCH if
rows are
found
No
Advantech 25 Krishnamurthy
Declaring a Cursor
When you declare a cursor, you name it and associate it
with a specific query. When you declare a cursor oracle
names an area of memory in server and associates select
statement with the cursor location.
At this stage, the query is PARSED
Parsing means
- checks for syntax (formation of SQL statement)
- checks for semantics (whether cols,tables,privileges etc
exists)
CURSOR cursor_name [(parameter[, parameter]...)]
[RETURN return_type] IS select_statement;
Ex:
cursor emp_cur is
select ename,sal,hiredate,deptno from emp where
deptno=20;
Advantech 26 Krishnamurthy
OPENing the Cursor
Opening the cursor executes the query and identifies the
result set, which consists of all rows that meet the query
search criteria.
For cursors declared using the FOR UPDATE clause, the
OPEN statement also locks those rows.
OPEN cursor_name;
Ex:OPEN emp_cur;
OPEN c1(emplname, 3000);
OPEN c1(SMITH, 1500); parameterized cursors
OPEN c1(emplname, esal);
Advantech 27 Krishnamurthy
Fetching with a Cursor
The FETCH statement retrieves the rows in the result set
one at a time. Each fetch retrieves the current row and
then advances the cursor to the next row in the result
set.
FETCH cursor_name INTO var1,var2,.. or record_list;
Ex:
FETCH c1 INTO my_empno, my_ename, my_deptno;
LOOP
FETCH c1 INTO my_record;
EXIT WHEN c1%NOTFOUND;
-- process data record
END LOOP;
Advantech 28 Krishnamurthy
Closing a Cursor
The CLOSE statement disables the cursor, and the result
set becomes undefined.
Once a cursor is closed, you can reopen it. Any other
operation on a closed cursor raises the predefined
exception INVALID_CURSOR.
CLOSE cursor_name;
Ex:
CLOSE emp_cur;
Advantech 29 Krishnamurthy
-returns number of rows processed %ROWCOUNT
-returns TRUE if cursor is
open
-always returns FALSE
since cursor is implicitly
closed
%ISOPEN
-complements %found attribute %NOTFOUND
-returns TRUE if LAST
FETCH is successful
-returns TRUE if last
statement is successful
%FOUND
EXPLICIT cursor IMPLICIT cursor ATTRIBUTE
CURSOR attributes
- returns status of the cursor
Advantech 30 Krishnamurthy
The FOR UPDATE Clause
Syntax:
Use explicit locking to deny access for the
duration of a transaction.
Lock the rows before the update or delete.
SELECT ...
FROM ...
FOR UPDATE [OF column_reference][NOWAIT];
Advantech 31 Krishnamurthy
The FOR UPDATE Clause
DECLARE
CURSOR empcursor IS
SELECT * FROM EMP WHERE sal > 1000 for update;
rec empcursor%rowtype;
newsal emp.sal%type;
BEGIN
OPEN empcursor;
LOOP
FETCH empcursor INTO rec;
EXIT WHEN empcursor%NOTFOUND;
IF rec.sal >= 3000 THEN
newsal:=rec.sal*1.5;
ELSE
newsal:=rec.sal*1.2;
END IF;
UPDATE EMP SET SAL=newsal WHERE EMPNO=rec.empno;
END LOOP;
CLOSE empcursor;
COMMIT;
END;
Advantech 32 Krishnamurthy
The "WHERE CURRENT OF" clause
The update statement within the loop uses the primary
key of the table, and is therefore a reasonably efficient
index lookup.
However, since we just fetched the row in question, why
should we need to perform an index lookup? Shouldn't we
already know where the row is?
In fact, the second index lookup is unnecessary. PL/SQL
(and the programmatic interfaces) can refer to the
current row selected by the cursor using the clause
"WHERE CURRENT OF cursor_name". Using this notation,
PL/SQL can use the row address (ROWID) stored in the
cursor structure to locate the row without an index
lookup.
Advantech 33 Krishnamurthy
WHERE CURRENT OF contd
DECLARE
CURSOR empcursor IS
SELECT * FROM EMP WHERE sal > 1000 for update;
rec empcursor%rowtype;
newsal emp.sal%type;
BEGIN
OPEN empcursor;
LOOP
FETCH empcursor INTO rec;
EXIT WHEN empcursor%NOTFOUND;
IF rec.sal >= 3000 THEN
newsal:=rec.sal*1.5;
ELSE
newsal:=rec.sal*1.2;
END IF;
UPDATE EMP SET SAL=newsal WHERE CURRENT OF empcursor;
END LOOP;
CLOSE empcursor;
COMMIT;
END;
The WHERE CURRENT OF clause eliminates the I/Os involved with an
index lookup and does improve the performance of the update
statement.
Advantech 34 Krishnamurthy
CURSOR FOR loop:
PL/SQL provides a special kind of FOR loop to process the rows
returned in an explicit CURSOR.
In a CURSOR FOR loop, a declared CURSOR is OPENed, FETCHed
from and CLOSEed automatically when all of the rows have be
processed.
Each iteration of the loop fetches a row from the active set into a
record, which is implicitly declared for use within the loop.
The loop is terminated automatically at the end of the iteration when
the last row was FETCHed.
FOR record_name IN cursor_name LOOP
statement1;
statement2;
. . .
END LOOP;
Advantech 35 Krishnamurthy
Handling Exceptions
An exception is an error in PL/SQL that is
raised during program execution.
An exception can be raised:
Implicitly by the Oracle server
Explicitly by the program
An exception can be handled:
By trapping it with a handler
By propagating it to the calling environment
By trapping and propagating it
Advantech 36 Krishnamurthy
Predefined Exception raised when
Advantech 37 Krishnamurthy
Advantech 38 Krishnamurthy
Advantech 39 Krishnamurthy
Advantech 40 Krishnamurthy
Handling Exceptions
Exception
raised
Is the
exception
trapped?
yes
Execute statements
in the EXCEPTION
section.
Terminate
gracefully.
no
Terminate
abruptly.
Propagate the
exception.
Advantech 41 Krishnamurthy
Predefined Exception Handler
Advantech 42 Krishnamurthy
Advantech 43 Krishnamurthy
Exceptions: Example
DECLARE
v_ename emp.ename%type;
BEGIN
SELECT ename INTO v_ename FROM EMP
WHERE DEPTNO=&DEPTNO;
dbms_output.put_line('Name is :'||v_ename);
EXCEPTION
WHEN no_data_found THEN
dbms_output.put_line('No employee in this dept');
WHEN too_many_rows THEN
dbms_output.put_line('Multiple rows fetched. Use cursors');
END;
/
Advantech 44 Krishnamurthy
Built-in Error Functions
SQLCODE - returns the error code of the most recently raised
exception in your block. If there is no error, SQLCODE returns 0.
SQLCODE also returns 0 when you call it outside of an exception
handler.
Oracle maintains a stack of SQLCODE values.
Suppose, for example, that function FUNC raises the VALUE_ERROR
exception (-6502). Within the exception section of FUNC, you call a
procedure PROC that raises DUP_VAL_ON_INDEX (-1). Within the
exception section of PROC, SQLCODE returns -1. When control
propagates back up to the exception section of FUNC, however,
SQLCODE will still return -6502. Run the sqlcode_test.sql file
(available on the book's web site) to see a demonstration of this
behavior.
Advantech 45 Krishnamurthy
SQLERRM
SQLERRM is a function that returns the error message for a
particular error code. If you do not pass an error code to
SQLERRM, it returns the error message associated with the value
returned by SQLCODE.
If SQLCODE is 0, SQLERRM returns this string:
ORA-0000: normal, successful completion
If SQLCODE is 1 (the generic user-defined exception error code),
SQLERRM returns this string: User-defined exception
Here is an example of calling SQLERRM to return the error message
for a particular code:
BEGIN
DBMS_OUTPUT.put_line (SQLERRM(-1403)); or 100
END;
SQL> /
ORA-01403: no data found
Advantech 46 Krishnamurthy
DBMS_UTILITY.FORMAT_ERROR_STACK
This built-in function, like SQLERRM, returns the message
associated with the current error (i.e., the value returned by
SQLCODE).
It differs from SQLERRM in two ways:
- Its length is not restricted; it will return the full error
message
string.
- You cannot pass an error code number to this function
Note that even though the name of the function includes the
word "stack" it doesn't return a stack of errors leading back to
the line on which the error was originally raised.
Advantech 47 Krishnamurthy
DBMS_UTILITY.FORMAT_ERROR_BACKTRACE
This function returns a formatted string that displays a stack of
programs and line numbers leading back to the line on which the
error was originally raised.
DBMS_UTILITY.FORMAT_CALL_STACK - returns a formatted
string showing the execution call stack inside your PL/SQL
application.
Advantech 48 Krishnamurthy
Example
CREATE OR REPLACE PROCEDURE proc1 IS
BEGIN
DBMS_OUTPUT.put_line('running proc1');
RAISE NO_DATA_FOUND;
END;
/
CREATE OR REPLACE PROCEDURE proc2 IS
BEGIN
DBMS_OUTPUT.put_line('calling proc1');
proc1;
END;
/
CREATE OR REPLACE PROCEDURE proc3 IS
BEGIN
DBMS_OUTPUT.put_line('calling proc2');
proc2;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.put_line('Error stack at top level:');
DBMS_OUTPUT.put_line(DBMS_UTILITY.format_error_backtrace);
END;
/
Advantech 49 Krishnamurthy
SQL> exec proc3;
calling proc2
calling proc1
running proc1
Error stack at top level:
ORA-06512: at "SCOTT.PROC1", line 4
ORA-06512: at "SCOTT.PROC2", line 4
ORA-06512: at "SCOTT.PROC3", line 4
Advantech 50 Krishnamurthy
Example
begin
dbms_output.put_line('Outer Executable section');
begin
dbms_output.put_line('Inner Executable section');
raise too_many_rows;
exception
when others then
dbms_output.put_line('Inner Exception');
dbms_output.put_line('Code:'||sqlcode||' Message:'||sqlerrm);
dbms_output.put_line('Error:'||dbms_utility.format_error_stack);
dbms_output.put_line('Backtrace:'||dbms_utility.format_error_backtrace);
raise no_data_found;
end;
exception
when others then
dbms_output.put_line('Outer Exception');
dbms_output.put_line('Code:'||sqlcode||' Message:'||sqlerrm);
dbms_output.put_line('Error:'||dbms_utility.format_error_stack);
dbms_output.put_line('Backtrace:'||dbms_utility.format_error_backtrace);
end;
Advantech 51 Krishnamurthy
Output:
Outer Executable section
Inner Executable section
Inner Exception
Code:-1422 Message:ORA-01422: exact fetch returns more than requested
number of rows
Error:ORA-01422: exact fetch returns more than requested number of rows
Backtrace:ORA-06512: at line 5 -- displays line no
Outer Exception
Code:100 Message:ORA-01403: no data found
ORA-01422: exact fetch returns more than requested number of rows
Error:ORA-01403: no data found
ORA-01422: exact fetch returns more than requested number of rows
Backtrace:ORA-06512: at line 12 -- displays line no
Advantech 52 Krishnamurthy
Trapping User-Defined Exceptions
Declarative
section
Executable
section
Exception-handling
section
Declare Raise Reference
Name the
exception
Explicitly raise
the exception by
using the RAISE
statement
Handle the raised
exception
Note : Example to be discussed
Advantech 53 Krishnamurthy
DECLARE
--declaring user defined exception name
salary_missing exception;
v_ename emp.ename%type;
v_sal emp.sal%type;
BEGIN
SELECT ename,sal INTO v_ename,v_sal FROM EMP WHERE
EMPNO=&EMPNO;
IF v_sal IS NULL THEN
--raising user defined exception explicitly
RAISE salary_missing;
ELSE
dbms_output.put_line(v_ename||' earns salary of '||v_sal);
END IF;
dbms_output.put_line('Rest of the executable code ......');
EXCEPTION
WHEN no_data_found THEN
dbms_output.put_line('No employee with this id.');
WHEN salary_missing THEN
-- handling user exception
dbms_output.put_line('Salary of '||v_ename||' is NULL !!!');
WHEN others THEN
dbms_output.put_line('Exception:'||SQLERRM);
END;
/ Advantech 54 Krishnamurthy
Trapping Non-Predefined Oracle
Server Errors
Declarative section
Declare
Name the
exception
Code PRAGMA
EXCEPTION_INIT
EXCEPTION section
Handle the raised
exception
Associate Reference
Advantech 55 Krishnamurthy
PRAGMA EXCEPTION_INIT
DECLARE
child_rows_found exception;
PRAGMA EXCEPTION_INIT(child_rows_found,-2292);
BEGIN
DELETE DEPT WHERE DEPTNO=10;
EXCEPTION
WHEN child_rows_found THEN
dbms_output.put_line('Cannot delete parent record.');
WHEN others THEN
dbms_output.put_line('Exception:'||SQLERRM);
END;
Advantech 56 Krishnamurthy
Example
CREATE OR REPLACE PROCEDURE add_emp(
p_empno IN emp.empno%type,
p_deptno IN emp.deptno%type)
IS
BEGIN
INSERT INTO emp(empno,deptno)VALUES(p_empno,p_deptno);
EXCEPTION
WHEN OTHERS THEN
DECLARE
v_errcode PLS_inTEGER := SQLCODE;
BEGIN
IF v_errcode = -1 THEN
DBMS_OUTPUT.put_line('Employee already exists');
RAISE;
ELSIF v_errcode = -2291 THEN
DBMS_OUTPUT.put_line('Invalid deptno');
RAISE;
ELSE
RAISE;
END IF;
END;
END add_emp;
Advantech 57 Krishnamurthy
The RAISE_APPLICATION_ERROR
Procedure
Syntax:
You can use this procedure to issue user-defined error
messages from stored subprograms.
You can report errors to your application and avoid
returning unhandled exceptions.
Arguments
- error_number must be in the range -2000 to -20999
- error_message must be text message of 2kb max
raise_application_error (error_number,
message[, {TRUE | FALSE}]);
Advantech 58 Krishnamurthy
The RAISE_APPLICATION_ERROR
Procedure
Is used in two places:
Executable section
Exception section
Returns error conditions to the user in a
manner consistent with other Oracle server
errors
Advantech 59 Krishnamurthy
Example
CREATE OR REPLACE PROCEDURE raise_salary(
p_empno IN emp.empno%type,
p_raise IN OUT emp.sal%type)
IS
esal emp.sal%type;
msal emp.sal%type;
BEGIN
SELECT e.sal,m.sal INTO esal,msal
FROM emp e,emp m
WHERE e.mgr=m.empno and e.empno=p_empno;
IF esal+p_raise >= msal THEN
raise_application_error(-20001,'Cannot exceed manager salary');
ELSE
UPDATE EMP SET SAL=esal+p_raise
WHERE EMPNO=p_empno RETURNING sal INTO p_raise;
dbms_output.put_line('Update successful.');
COMMIT;
END IF;
dbms_output.put_line('Rest of executable code...');
EXCEPTION
WHEN no_data_found THEN
dbms_output.put_line('No employee with this ID');
END;
Advantech 60 Krishnamurthy
Dependencies
Table
View
Database trigger
Procedure
Function
Package body
Package specification
User-defined object
and collection types
Function
Package specification
Procedure
Sequence
Synonym
Table
View
User-defined object
and collection types
Referenced objects Dependent objects
Advantech 61 Krishnamurthy
Dependencies
View or
procedure
Direct
dependency
Referenced
Indirect
dependency
Direct
dependency
Dependent
Table
Referenced
xxxxxxxxxxxxxx
vvvvvvvvvvvvvv
xxxxxxxxxxxxxx
vvvvvvvvvvvvvv
xxxxxxxxxxxxxx
vvvvvvvvvvvvvv
xxxxxxxxxxxxxx
vvvvvvvvvvvvvv
xxxxxxxxxxxxxx
vvvvvvvvvvvvvv
Procedure
Dependent
Advantech 62 Krishnamurthy
Dependency Management
- Another important phase of PL/SQL compilation and execution is
the checking of program dependencies.
- A dependency (in PL/SQL) is a reference from a stored program to
some Oracle object outside the program.
- Server-based PL/SQL programs can have dependencies on tables,
views, types, procedures, functions, sequences, synonyms, or
package specifications, but not on package bodies or type bodies.
Oracle's basic dependency objective for PL/SQL is
Do not allow a program to run if any of the objects on which it
depends have changed since it was compiled.
Note: most of dependency management happens automatically,
from the tracking of dependencies to the recompilation required to
keep everything synchronized.
Advantech 63 Krishnamurthy
Dependencies in PL/SQL
A simple illustration:
I have a package epkg which contains procedures, functions, record
types, collections etc related to emp table. Description is as shown
Advantech 64 Krishnamurthy
To view data dictionary information regarding the same I would use
user_objects and user_dependencies
Oracle has used its DIANA to determine a list of other objects that
EPKG needs in order to compile successfully.
Advantech 65 Krishnamurthy
Dependency graph of EPKG package
standard
PACKAGE
dbms_standard
PACKAGE
dbms_output
PACKAGE
epkg BODY epkg SPEC
emp TABLE
Advantech 66 Krishnamurthy
Let us find out which objects depends on EMP table and when we
modify structure of EMP table you can observe the dependent objects
status
Advantech 67 Krishnamurthy
You can use deptree procedure to view the dependency tree.
Run following script in SYS schema
C:\app\Administrator\product\11.1.0\db_1\RDBMS\ADMIN\utldtree.sql
SQL> EXEC DEPTREE_FILL('TABLE', 'SCOTT', 'EMP');
SQL> SELECT * FROM IDEPTREE;
DEPENDENCIES
-----------------------------------------------------------------------
PACKAGE SCOTT.EPKG
CURSOR <shared>."LOCK TABLE "EMP" IN ROW EXCLUSIVE MODE NOWAIT "
PACKAGE BODY SCOTT.EPKG
PROCEDURE SCOTT.RAISE_SALARY
PACKAGE BODY SCOTT.EPKG
TABLE SCOTT.EMP
Note : Using packages in your design can break the cycle of
dependencies and recompilations.
Advantech 68 Krishnamurthy
Healing Invalids
In any event, no PL/SQL program marked as invalid will run until a
successful recompilation restores its validity. There are at least three
ways that can happen:
By hand - Using an explicit ALTER command to recompile the
package
By script - Using a program that looks for invalid packages and
issues the ALTER commands for you
Automatically - Relying on Oracle's built-in recompilation rules
Advantech 69 Krishnamurthy
Recompiling by hand
The "by hand" method is simple, but it can be tedious.
ALTER PACKAGE epkg COMPILE BODY;
ALTER PROCEDURE raise_salary COMPILE;
Recompiling by script
Various scripts exist that can help you reduce the tedium of these
recompilations. Note that these must be run while logged in to the
database as SYSDBA.
utlip.sql - Invalidates and recompiles all PL/SQL code and views
in the entire database.
utlrp.sql - Recompiles all of the invalid objects in serial and is
appropriate for single-processor hardware.
utlrcmp.sql - Like utlrp.sql, recompiles all invalid objects, but in
parallel
Advantech 70 Krishnamurthy
Automatic recompilation
Automatic recompilation, is simpler, but it isn't without drawbacks.
If you merely execute one of the programs implemented in the EPKG
package body, Oracle will recompile it just prior to execution.
Production environments are likely to have strict policies on when
you can and cannot recompile programs. That's because installing a
new version of a PL/SQL program can force a lot of recompilation and
can have disastrous side effects on programs currently running.
You will probably want to run a script similar to utlrp.sql to find and
recompile all invalid objects. Your DBA should help you schedule an
upgrade procedure, which should include running a recompilation
script.
Aside from a potentially unscheduled drain on performance, the
biggest drawback to Oracle's automatic recompilation feature is that
it can interfere with packages that are currently running.
This happens because automatically recompiling a package that is
currently running invalidates the package.
Advantech 71 Krishnamurthy
Automatic recompilation ..
Not only that, Oracle shares the program's bytecode among different
sessions, so this invalidation affects not just the session that
triggered the recompilation, but every Oracle session that has
instantiated the package! Consequences of this devastation include
the following:
- Executions terminate with an ORA-04068 error
- All public and private package variables assume their default
values; if you haven't supplied an explicit default value, it will revert
to NULL. This effect applies to any package that the session has
instantiated, not just the one that's getting recompiled. So, if you
were in the middle of any computations that assign values to
package variables, you will lose the contents of those variables.
- DBMS_OUTPUT stops working. Well, not really, but if you had
previously enabled it, Oracle will disable it. This occurs because its
on/off switch is really a package variable, and resetting the package
state causes this variable to revert to its default, which is off.
Advantech 72 Krishnamurthy
Remote Dependencies
Server-based PL/SQL immediately becomes invalid whenever there's
a change in a local object on which it depends. However, if it depends
on an object on a different computer and that object changes, Oracle
does not attempt to invalidate the calling PL/SQL program in real
time. Instead, Oracle defers the checking until runtime.
Here is a program that has a remote dependency on the procedure
recompute_prices which lives across the database link
findat.ldn.world:
PROCEDURE synch_em_up (
tax_site_in IN VARCHAR2,
since_in IN DATE)
IS
BEGIN
IF tax_site_in = 'LONDON' THEN
recompute_prices@findat.ldn.world(cutoff_time => since_in);
END IF;
.
Advantech 73 Krishnamurthy
If you recompile the remote procedure and some time later try to run
synch_em_up, you are likely to get an ORA-04062 error with
accompanying text such as timestamp (or signature) of package
"SCOTT.recompute_prices" has been changed.
If your call is still legal, Oracle will recompile synch_em_up, and if it
succeeds, its next invocation should run without error.
To understand Oracle's remote procedure call behavior, you need to
know that the PL/SQL compiler always stores two kinds of
information about each referenced remote procedure: its timestamp
and its signature:
timestamp - The most recent date and time (down to the second)
when an object's specification was reconstructed, as given by the
TIMESTAMP (date datatype) column in the USER_OBJECTS view.
For PL/SQL programs, this is not necessarily the same as the most
recent compilation time because it's possible to recompile an object
without reconstructing its specification.
Advantech 74 Krishnamurthy
Signature
A footprint of the actual shape of the object's specification.
Signature information includes the object's name and the
ordering, datatype family, and mode of each parameter.
So when I compiled synch_em_up, Oracle retrieved both the
timestamp and the signature of the remote procedure called
recomputed_prices, and stored a representation of them with the
bytecode of synch_em_up.
How do you suppose Oracle uses this information at runtime?
The model is simple: it uses either the timestamp or the signature,
depending on the current value of the parameter
REMOTE_DEPENDENCIES_MODE.
If that timestamp or signature information, which is stored in the
local program's bytecode, doesn't match the actual value of the
remote procedure at runtime, you get the ORA-04062 error.
Advantech 75 Krishnamurthy
Oracle's default remote dependency mode is the timestamp method,
but this setting can sometimes cause unnecessary recompilations.
The DBA can change the system-wide setting via the database
initialization file or an ALTER SYSTEM command; an application
developer can set it for the current session using the following
command:
ALTER SESSION SET REMOTE_DEPENDENCIES_MODE = SIGNATURE;
Advantech 76 Krishnamurthy
Using Oracle-Supplied Packages
Oracle-supplied packages:
Are provided with the Oracle server
Extend the functionality of the database
Enable access to certain SQL features that are normally
restricted for PL/SQL
For example, the DBMS_OUTPUT package was
originally designed to debug PL/SQL programs.
Advantech 77 Krishnamurthy
Some of the Oracle-Supplied Packages
Here is an abbreviated list of some Oracle-
supplied packages:
DBMS_ALERT
DBMS_LOCK
DBMS_SESSI ON
DBMS_OUTPUT
HTP
UTL_FI LE
UTL_MAI L
DBMS_SCHEDULER
Advantech 78 Krishnamurthy
DBMS_OUTPUT Package
The DBMS_OUTPUT package enables you to send
messages from stored subprograms and triggers.
PUT and PUT_LI NE place text in the buffer.
GET_LI NE and GET_LI NES read the buffer.
Use SET SERVEROUTPUT ONto display messages in
SQL*Plus. (The default is OFF.)
PUT_LINE
GET_LINE
PUT
NEW_LINE
GET_LINES
SET SERVEROUT ON [SIZE n]
EXEC proc
Buffer
Output
Advantech 79 Krishnamurthy
UTL_FILE Package
The UTL_FI LE package extends PL/SQL programs to
read and write operating system text files.
It provides a restricted version of operating system stream file
I/O for text files.
It can access files in operating system directories defined by a
CREATE DI RECTORY statement.
EXEC proc
O/S file UTL_FILE
CREATE DIRECTORY
my_dir AS '/dir'
Advantech 80 Krishnamurthy
UTL_FILE package
DBA configuration
connect system/<password> as sysdba
CREATE OR REPLACE DIRECTORY FILE_DIR AS 'C:\TEMP_FILES';
GRANT READ,WRITE ON DIRECTORY FILE_DIR TO PUBLIC;
CONNECT scott/tiger
Advantech 81 Krishnamurthy
writing emp table data into file
create or replace procedure write_emp(
path in varchar2,
filename in varchar2)
is
output_file utl_file.file_type;
cursor empcursor IS
SELECT empno,ename,sal FROM EMP;
begin
output_file := utl_file.fopen (PATH,FILENAME, 'w');
for erec in empcursor loop
utl_file.put_line(output_file,
erec.empno||','||erec.ename||','||erec.sal);
end loop;
utl_file.fclose(output_file);
exception
when others then
dbms_output.put_line(SQLERRM);
end;
exec write_emp('FILE_DIR','empdata.txt');
Advantech 82 Krishnamurthy
Reading contents of a file
create or replace procedure read_file(
path in varchar2,
filename in varchar2)
is
input_file utl_file.file_type;
input_buffer varchar2(4000);
begin
input_file := utl_file.fopen (path,filename,'R');
dbms_output.put_line('Output:');
loop
utl_file.get_line (input_file, input_buffer);
dbms_output.put_line(input_buffer);
end loop;
utl_file.fclose(input_file);
exception
when no_data_found then
null;
when others then
dbms_output.put_line(SQLERRM);
end;
/
exec read_file('FILE_DIR','empdata.txt');
Advantech 83 Krishnamurthy
Advanced Cursor Concepts
Cursor Variables and REF CURSORs
A cursor variable is a variable that points to or
references an underlying cursor.
Unlike an explicit cursor, which names the PL/SQL work
area for the result set, a cursor variable is a reference to
that work area.
Explicit and implicit cursors are static in that they are
tied to specific queries.
The cursor variable can be opened for any query, even
for different queries within a single program execution.
Advantech 84 Krishnamurthy
The most important benefit of the cursor variable is that it provides a
mechanism for passing results of queries (the rows returned by fetches
against a cursor) between different PL/SQL programs even between
client and server PL/SQL programs.
Advantech 85 Krishnamurthy
It is important to distinguish between declaring a cursor variable and
creating an actual cursor object the result set identified by the cursor
SQL statement.
A constant is nothing more than a value, whereas a variable points to its
value. Similarly, a static cursor acts as a constant, whereas a cursor
variable references or points to a cursor object.
These distinctions are shown in figure. Notice that two different cursor
variables in different programs are both referring to the same cursor
object.
Advantech 86 Krishnamurthy
Cursor Variables REF CURSOR
Cursor variables are like C pointers, which hold the
memory location (address) of some item instead of the
item itself.
A REF CURSOR is basically a data type.
A variable created based on such a data type is generally
called a cursor variable.
A cursor variable can be associated with different queries
at run-time.
The primary advantage of using cursor variables is their
capability to pass result sets between sub programs (like
stored procedures, functions, packages etc.).
Advantech 87 Krishnamurthy
Defining REF CURSOR Types
To create cursor variables, you take two steps.
First, you define a REF CURSOR type, then declare cursor
variables of that type.
You can define REF CURSOR types in any PL/SQL block,
subprogram, or package
TYPE ref_type_name IS REF CURSOR [RETURN
return_type];
where ref_ type_ name is a type specifier used in
subsequent declarations of cursor variables and
return_ type must represent a record or a row in a
database table.
Then declare variable of ref_type_name
Advantech 88 Krishnamurthy
SYS_REFCURSOR weak reference type
Oracle has pre-defined ref cursor type in standard package using
which you can declare a variable.
create or replace procedure emp_refcur(cur_var out sys_refcursor)
is
begin
open cur_var for select * from emp;
end;
/
SQL> variable e_curvar refcursor
SQL> exec emp_refcur(:e_curvar)
SQL> print e_curvar
Advantech 89 Krishnamurthy
Dynamic Queries With REF CURSOR's
Oracle supports dynamic queries via the OPEN FOR USING
statement.
A string literal or string variable is supplied in the OPEN FOR USING
statement to the SELECT command.
OPEN name FOR dynamic_string
[ USING bind_arg [, bind_arg_2 ]...];
name is the identifier of a previously declared cursor variable.
dynamic_string is a string literal or string variable containing a
SELECT command.
bind_arg, bind_arg_2... are bind arguments that are used to pass
variables to corresponding placeholders in the SELECT command
when the cursor variable is opened.
The placeholders are identifiers prefixed by a colon character.
Advantech 90 Krishnamurthy
Example
CREATE OR REPLACE PROCEDURE dept_query (
p_deptno emp.deptno%TYPE, p_sal emp.sal%TYPE)
IS
emp_refcur SYS_REFCURSOR;
v_empno emp.empno%TYPE;
v_ename emp.ename%TYPE;
p_query_string VARCHAR2(100);
BEGIN
p_query_string := 'SELECT empno, ename FROM emp WHERE ' ||
'deptno = :dno AND sal >= :esal';
OPEN emp_refcur FOR p_query_string USING p_deptno, p_sal;
DBMS_OUTPUT.PUT_LINE('EMPNO ENAME');
DBMS_OUTPUT.PUT_LINE('----- -------');
LOOP
FETCH emp_refcur INTO v_empno, v_ename;
EXIT WHEN emp_refcur%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(v_empno || ' ' || v_ename);
END LOOP;
CLOSE emp_refcur;
END;
Advantech 91 Krishnamurthy
COLLECTION
A collection is an ordered group of elements, all of the
same type.
Each element has a unique subscript that determines
its position in the collection
Advantech 92 Krishnamurthy
Types of Collections
Associative Arrays : to hold arbitrary no of elements.
Indexing is by pls_integer, binary_integer, varchar2, positive
and natural
Nested tables hold an arbitrary number of elements. They use
sequential numbers as subscripts.
Varrays (variable-size arrays) hold a fixed number of
elements (although you can change the number of elements at
runtime). They use sequential numbers as subscripts.
Note: A nested table & varrays are of object type and therefore
needs to first be initialized with a constructor before being used.
Advantech 93 Krishnamurthy
Advantech 94 Krishnamurthy
Associative Arrays
Objects of the TABLE type are called INDEX BY tables.
They are modeled as database tables (but not the
same as).
Associative arrays use a primary key to provide you
with array-like access to rows.
An Associative Array:
Is similar to an array in other languages
Must contain two components:
A primary key is data that indexes the INDEX BY
table
A column of a scalar or record data type, which
stores the INDEX BY table elements
Can increase dynamically because it is
unconstrained
Advantech 95 Krishnamurthy
Creating an I NDEXBY Table
Syntax:
TYPE type_name IS TABLE OF
{column_type | variable%TYPE
| table.column%TYPE} [NOT NULL]
| table.%ROWTYPE
[INDEX BY datatype];
identifier type_name;
...
TYPE ename_table_type IS TABLE OF emp.ename%TYPE
INDEX BY BINARY_INTEGER;
ename_table ename_table_type;
...
Example:
Declare an INDEX BY table to store names.
Advantech 96 Krishnamurthy
I NDEXBY Table Structure
Unique identifier Column
... ...
1 J ONES
2 SMITH
3 KING
... ...
BI NARY_I NTEGER Scalar
Advantech 97 Krishnamurthy
Example :
DECLARE
TYPE IntDataTyp IS TABLE OF integer
INDEX BY BINARY_INTEGER;
inttab IntDataTyp;
BEGIN
inttab(1):=10;
inttab(12):=20;
inttab(25):=30;
dbms_output.put_line(inttab(1)||','||inttab(12)||','||inttab(25));
END;
Advantech 98 Krishnamurthy
Note : No DML (except delete) or transactions can be
implemented on various collections
Built-in Functions and Procedures for collections
Operator Description
COUNT Returns the number of elements currently contained in the PL/SQL table.
DELETE Deletes one or more elements from the PL/SQL table.
EXISTS Returns FALSE if a reference to an element at the specified index would
raise the NO_DATA_FOUND exception.
FIRST Returns the smallest index of the PL/SQL table for which an element is
defined.
LAST Returns the greatest index of the PL/SQL table for which an element is
defined.
NEXT Returns the smallest index of the PL/SQL table containing an element
which is greater than the specified index.
PRIOR Returns the greatest index of the PL/SQL table containing an element
which is less than the specified index.
Advantech 99 Krishnamurthy
EXTEND Extends the number of elements in collection.EXTEND;
a collection. Cannot be used on (extends collection by a
single element) associative arrays or other collections
that have not been initialized.
collection.EXTEND(n);.(extends collection by n
elements)
collection.EXTEND(n, I); (extends collection by n
elements by copying value in element indexed by I)
TRIM Removes elements from the end collection.TRIM;.
of a collection. removes a single element from end of
collection
collection.TRIM(n);. removes n elements from end of
collection
Advantech 100 Krishnamurthy
Deleting rows in collections
To delete specific row
<table_name>.delete(<index_number>)
To delete all the rows
<table_name>.delete
To delete range of rows
<tablename>.DELETE (start_index_in IN INTEGER,
end_index_in IN INTEGER);
Advantech 101 Krishnamurthy
I NDEXBY Table of Records
DECLARE
TYPE dept_table_type IS TABLE OF dept%ROWTYPE
INDEX BY BINARY_INTEGER;
dept_table dept_table_type;
-- Each element of dept_table is a record
to refer each field
dept_table(index).field_name must be used
Define a TABLE variable with a permitted PL/SQL data type.
Declare a PL/SQL variable to hold department information.
Example: Example:
Advantech 102 Krishnamurthy
Example using CURSOR FOR LOOP
SET SERVEROUTPUT ON
DECLARE
TYPE emp_tabtype IS TABLE OF EMP%ROWTYPE INDEX BY
BINARY_INTEGER;
EMPREC emp_tabtype;
BEGIN
for rec in (select * from emp) loop
EMPREC(rec.empno):=rec;
END LOOP;
for i in EMPREC.FIRST..EMPREC.LAST LOOP
if EMPREC.exists(i) then
dbms_output.put_line(i||','||EMPREC(i).ENAME);
end if;
end loop;
END;
Advantech 103 Krishnamurthy
Nested Tables
nested tables can be considered one-column database tables.
oracle stores the rows of a nested table in no particular order.
when you retrieve the nested table into a PL/SQL variable,
the rows are given consecutive subscripts starting at 1. That
gives you array-like access to individual rows.
Advantech 104 Krishnamurthy
NESTED ARRAY vs ARRAY
Arrays are dense and have a fixed upper bound, but nested
tables are initially dense but become sparse and are unbounded
In arrays you cannot delete elements
In nested table you can delete elements using the built-in
procedure DELETE. That might leave gaps in the index, but
the built-in function NEXT lets you iterate over any series of
subscripts.
Advantech 105 Krishnamurthy
Understanding Varrays
Items of type VARRAY are called varrays.
They allow you to associate a single identifier with an entire
collection. This association lets you manipulate the collection
as a whole and reference individual elements easily.
To reference an element, you use standard subscripting syntax
A varray has a maximum size
Advantech 106 Krishnamurthy
Defining Collection Types
You can define TABLE and VARRAY types in the
declarative part of any PL/SQL block, subprogram, or
package.
Nested Tables
TYPE type_name IS TABLE OF element_type [NOT NULL]
type_name is a type specifier used later to declare collections.
element_type is any PL/SQL datatype
Varrays
TYPE type_name IS {VARRAY | VARYING ARRAY}
( size_limit) OF element_type [NOT NULL]
type_name and element_type are the same as for nested tables
size_limit is a positive integer
Advantech 107 Krishnamurthy
Example:
DECLARE
TYPE NumList IS TABLE OF VARCHAR2(12);
nums NumList := NumList(10,20,30);
BEGIN
for i in 1..3 loop
DBMS_OUTPUT.PUT_LINE(nums(i));
end loop;
nums(1):='A';
nums(2):=60;
nums(3):='welcome';
for i in 1..3 loop
DBMS_OUTPUT.PUT_LINE(nums(i));
end loop;
END;
Advantech 108 Krishnamurthy
DECLARE
TYPE dname_nt_type IS TABLE OF dept.dname%type;
dnames dname_nt_type:=dname_nt_type();
BEGIN
FOR rec IN (SELECT dname from dept) LOOP
dnames.EXTEND;
dnames(dnames.LAST):=rec.dname;
END LOOP;
FOR j IN dnames.FIRST..dnames.LAST LOOP
dbms_output.put_line(j||'-'||dnames(j));
END LOOP;
END;
/
Advantech 109 Krishnamurthy
Needs
initialization
(except in bulk
collect)
Does not need
initialization
initialization
Bound by size
Can hold
arbitrary no of
elements
No of
elements
Always
starts from
1
Can start
from any
index
number
Start
index
Cannot
contain gaps
Initially dense,
after deletion
becomes
sparse
Can contain
gaps
gaps
Cannot
create
schema level
types
INDEX BY
clause is
used
Associative
Array
Varray
Schema
level types
can be
created
No index
by clause
Nested
Tables
Schema
types
index collection
Comparing Associative array, nested table & varray
Advantech 110 Krishnamurthy
SQL
DATA
Context Switching
Performance Gains
Performance Gains
with Bulk Binding
with Bulk Binding
PL/SQL Engine
SQL Engine
SQL Statement
Executor
Procedural statement
Executor
BULK COLLECT INTO clause (ie.,BULK FETCH INTO)
Advantech 111 Krishnamurthy
The Oracle server has three execution engines: one each
for PL/SQL, SQL, and Java.
- When running PL/SQL blocks and subprograms, the
PL/SQL engine runs procedural statements but sends the
SQL statements to the SQL engine, which parses and
executes the SQL statement and, in some cases, returns
data to the PL/SQL engine. During execution, every SQL
statement causes a context switch between the two
engines, which results in a performance penalty.
- Performance can be improved substantially by
minimizing the number of context switches required to
run a particular block or subprogram. When a SQL
statement runs inside a loop that uses collection elements
as bind variables, the large number of context switches
required by the block can cause poor performance.
Advantech 112 Krishnamurthy
Bulk collect is one form of bulk processing (bulk
insert, delete and update are others).
Bulk collect is supported by the following
statements and clauses:
FETCH INTO
SELECT INTO
RETURNING INTO
Advantech 113 Krishnamurthy
Using FETCH cur_name BULK COLLECT INTO
collection
This statement avoid context switching between PL/SQL
engine and SQL engine for fetching rows into colleciton
DECLARE
CURSOR empcursor is select * from emp;
TYPE erectabtype IS TABLE OF emp%rowtype;
etab erectabtype;
BEGIN
OPEN empcursor;
FETCH empcursor BULK COLLECT INTO etab;
CLOSE empcursor;
FOR idx IN etab.first..etab.last LOOP
dbms_output.put_line(idx||','||etab(idx).ename);
END LOOP;
END;
Advantech 114 Krishnamurthy
Using SELECT col_list BULK COLLECT INTO
collection
DECLARE
deptno_tab dbms_sql.number_table; -- inbuilt type
ename_tab dbms_sql.varchar2_table;
BEGIN
SELECT ename,deptno BULK COLLECT INTO ename_tab,deptno_tab
FROM EMP WHERE SAL > 2000;
FOR i IN 1..ename_tab.COUNT LOOP --or sql%rowcount
dbms_output.put_line(ename_tab(i)||','||deptno_tab(i));
END LOOP;
END;
/
Advantech 115 Krishnamurthy
RETURNING into arrays
DECLARE
TYPE emp_rec_type IS RECORD(
empno EMP.EMPNO%TYPE,
ename EMP.ENAME%TYPE);
TYPE emp_tab_type IS TABLE OF emp_rec_type
INDEX BY binary_integer;
emptab emp_tab_type;
BEGIN
UPDATE EMP SET SAL=SAL*1.15
WHERE DEPTNO=30
RETURNING empno,ename BULK COLLECT INTO emptab;
FOR i IN 1..emptab.LAST LOOP
dbms_output.put_line(emptab(i).empno||','||emptab(i).ename);
END LOOP;
END;
Advantech 116 Krishnamurthy
INSERT with RECORD Bind
CREATE TABLE retired_employees
AS SELECT * FROM EMP WHERE 1=0;
DECLARE
v_erec emp%rowtype;
BEGIN
SELECT * INTO v_erec FROM EMP WHERE EMPNO=7566;
INSERT INTO retired_employees VALUES v_erec;
END;
Bulk INSERTing with a record.
DECLARE
TYPE emprectype IS TABLE OF emp%ROWTYPE;
retirees emprectype;
BEGIN
SELECT * BULK COLLECT INTO retirees FROM EMP;
FOR indx in retirees.first..retirees.last LOOP
INSERT INTO retired_employees VALUES retirees(indx);
END LOOP;
END;
Advantech 117 Krishnamurthy
UPDATE SET ROW with RECORD Bind
Oracle gives you an easy and powerful way to update an
entire row in a table from a record: the SET ROW clause.
The ROW keyword is functionally equivalent to *.
DECLARE
v_erec emp%rowtype;
BEGIN
SELECT * INTO v_erec FROM EMP WHERE EMPNO=7566;
v_erec.sal:=v_erec.sal*1.5;
v_erec.job:='SR CLERK';
UPDATE emp SET ROW = v_erec WHERE empno=v_erec.empno;
END;
Advantech 118 Krishnamurthy
RETURNING into a record from a DELETE statement.
DECLARE
v_erec emp%ROWTYPE;
BEGIN
DELETE FROM emp WHERE empno = 7566
RETURNING empno, ename, job, mgr, hiredate, sal,
comm, deptno INTO v_erec;
dbms_output.put_line('Deleted :'||v_erec.empno);
END;
Advantech 119 Krishnamurthy
You can also RETURN less columns
Ex - 1
DECLARE
id emp.ename%TYPE;
name emp.ename%TYPE;
BEGIN
DELETE FROM emp WHERE empno = 7566
RETURNING empno, ename INTO id,name;
dbms_output.put_line('Deleted :'||id||','||name);
END;
Ex - 2
DECLARE
TYPE key_rec_type IS RECORD (
id NUMBER, name VARCHAR2 (100));
v_erec key_rec_type;
BEGIN
DELETE FROM emp WHERE empno = 7566
RETURNING empno, ename INTO v_erec;
dbms_output.put_line('Deleted :'||v_erec.id||','||v_erec.name);
END;
Advantech 120 Krishnamurthy
FORALL statement
Ex:
CREATE TABLE EMPLOY IS
SELECT * FROM EMP WHERE 1=0;
DECLARE
TYPE erectabtype IS TABLE OF employ%rowtype;
etab erectabtype;
CURSOR empcursor IS SELECT * FROM EMP;
BEGIN
OPEN empcursor;
FETCH empcursor BULK COLLECT INTO etab;
FORALL i IN etab.first..etab.last
insert into employ values etab(i);
END;
Note : can be used only if indexed numbers are
sequential
Advantech 121 Krishnamurthy
Using RETURNING & FORALL
DECLARE
TYPE EmpTabType IS TABLE OF EMP.EMPNO%TYPE;
emps EmpTabType;
BEGIN
DELETE FROM EMP WHERE HIREDATE LIKE '%81'
RETURNING empno BULK COLLECT INTO emps;
dbms_output.put_line('Deleted Records are');
FORALL i IN emps.first..emps.last
INSERT INTO DELETED_EMPS VALUES(emps(i));
END;
Advantech 122 Krishnamurthy
The INDICES OF clause replaces the lower_bound
..upper_bound to indicate that all valid index values
should be processed, even if there are gaps. It looks like
this:
FORALL index_name IN INDICES OF collection_name
[BETWEEN lower_bound AND upper_bound]
sql_statement;
You can still limit the range processed by using the
BETWEEN syntax, which is optional.
Ex:
FORALL i IN INDICES OF etab
insert into employ values etab(i);
Note: can be used even if indexes are non-sequential
(sparse)
Advantech 123 Krishnamurthy
CREATE TABLE ENAME_TABLE(names varchar2(12));
DECLARE
TYPE ename_table_type IS TABLE OF varchar2(12)
index by pls_integer;
enames ename_table_type;
BEGIN
FOR rec IN (select empno,ename from emp) LOOP
enames(rec.empno):=rec.ename;
END LOOP;
FORALL x IN INDICES OF enames
insert into ename_table values(enames(x));
END;
Advantech 124 Krishnamurthy
The VALUES OF clause enables you to process
the main collection in a different sequence. You
create a second collection containing only the
index numbers you want to process, in the order
you want them processed.
The statement then becomes:
FORALL index_name IN VALUES OF
index_collection
sql_statement;
Note:
-index cannot be used in iteration
-dbms_output.put_line debug statement cannot be used
in iteration
Advantech 125 Krishnamurthy
CREATE TABLE ENAME_TABLE(names varchar2(12));
DECLARE
TYPE empno_tab_type IS TABLE OF emp.ename%type
INDEX BY pls_integer;
empnames empno_tab_type;
TYPE index_table_type IS TABLE OF pls_integer;
idx_tab index_table_type;
BEGIN
FOR rec IN (select empno,ename from emp) LOOP
empnames(rec.empno):=rec.ename;
END LOOP;
select empno bulk collect into idx_tab from emp;
FORALL x IN VALUES OF idx_tab
insert into ename_table select ename from emp where
ename=empnames(x);
END;
Advantech 126 Krishnamurthy
Nested Table Multiset Operations
Advantech 127 Krishnamurthy
Advantech 128 Krishnamurthy
Example
DECLARE
type int_nt_type IS TABLE OF integer;
t1 int_nt_type:=int_nt_type(10,20,30,40);
t2 int_nt_type:=int_nt_type(10,10,20,50);
t3 int_nt_type:=int_nt_type();
BEGIN
dbms_output.put_line('Testing weather t3 is empty...');
if t3 IS EMPTY THEN
dbms_output.put_line('t3 is empty');
end if;
dbms_output.put_line('Comparing t1 and t2.....');
IF t1=t2 THEN
dbms_output.put_line('t1=t2');
ELSE
dbms_output.put_line('t1!=t2');
END IF;
Advantech 129 Krishnamurthy
dbms_output.put_line('Distinct of t2 copied to t3');
t3:=set(t2);
for i IN t3.first..t3.last loop
dbms_output.put_line(t3(i));
end loop;
dbms_output.put_line('t1 multiset union [distinct] t2');
t3:=t1 multiset union distinct(t2);
for i IN t3.first..t3.last loop
dbms_output.put_line(t3(i));
end loop;
dbms_output.put_line('t1 multiset intersect t2');
t3:=t1 multiset intersect(t2);
for i IN t3.first..t3.last loop
dbms_output.put_line(t3(i));
end loop;
END;
Advantech 130 Krishnamurthy
VARRAYS
DECLARE
TYPE NumList IS VARRAY(3) OF VARCHAR2(12);
nums NumList := NumList(10,20,30);
BEGIN
for i in 1..3 loop
DBMS_OUTPUT.PUT_LINE(nums(i));
end loop;
nums(1):='A';
nums(2):=60;
nums(3):='welcome';
for i in 1..3 loop
DBMS_OUTPUT.PUT_LINE(nums(i));
end loop;
END;
Advantech 131 Krishnamurthy
Nested table column example
CREATE TYPE HOBBY_TAB_TYPE IS TABLE OF VARCHAR2(15);
CREATE TABLE EMPHOBBIES(
empno NUMBER(4),
ename VARCHAR2(12),
hobbies HOBBY_TAB_TYPE)
NESTED TABLE hobbies STORE AS HOBBY_EXT_TAB;
INSERT INTO EMPHOBBIES VALUES(7369,'SMITH',
HOBBY_TAB_TYPE('FOOTBALL','CRICKET','MOVIES','SWIMMING'))
INSERT INTO EMPHOBBIES VALUES(7566,'JONES',
HOBBY_TAB_TYPE('TV','SNOOKER','READING'));
SELECT * FROM EMPHOBBIES;
SELECT * FROM TABLE(SELECT HOBBIES FROM EMPHOBBIES WHERE
EMPNO=7369);
Advantech 132 Krishnamurthy
SELECT E.EMPNO,E.ENAME,H.*
FROM EMPHOBBIES E,TABLE(E.HOBBIES) H;
INSERT INTO TABLE(SELECT HOBBIES FROM EMPHOBBIES
WHERE EMPNO=7566)
VALUES('TENNIS');
UPDATE TABLE(SELECT HOBBIES FROM EMPHOBBIES
WHERE EMPNO=7369)
SET COLUMN_VALUE='READING' WHERE
COLUMN_VALUE='SWIMMING';
DELETE TABLE(SELECT HOBBIES FROM EMPHOBBIES
WHERE EMPNO=7369)
WHERE COLUMN_VALUE='CRICKET';
Advantech 133 Krishnamurthy
Using collections in database columns
CREATE TYPE ITEM_TYPE IS OBJECT(
ITEM_NAME VARCHAR2(12),
ITEM_QTY NUMBER(2),
ITEM_PRICE NUMBER(9,2));
CREATE TYPE ITEM_TAB_TYPE IS TABLE OF ITEM_TYPE;
CREATE TABLE INVOICE(
INVOICE_NUM NUMBER(4),
CUST_NAME VARCHAR2(12),
ITEM_DETAILS ITEM_TAB_TYPE)
NESTED TABLE ITEM_DETAILS STORE AS ITEM_EXT_TABLE;
DESC INVOICE
DESC ITEM_EXT_TABLE
Advantech 134 Krishnamurthy
INSERT INTO INVOICE VALUES(1001,'PRAKASH',
ITEM_TAB_TYPE(
ITEM_TYPE('P4 CPU',2,4500),
ITEM_TYPE('INTEL M B',2,4750),
ITEM_TYPE('512MB RAM',3,1500)));
INSERT INTO INVOICE VALUES(1002,'MOHAN',
ITEM_TAB_TYPE(
ITEM_TYPE('KEYBOARD',5,450),
ITEM_TYPE('SPEAKERS',3,370),
ITEM_TYPE('ATX CABINET',3,1150),
ITEM_TYPE('80GB HDD',2,5500)))
SELECT * FROM INVOICE;
SELECT ITEM_NAME,ITEM_QTY,ITEM_PRICE
FROM THE (SELECT ITEM_DETAILS
FROM INVOICE WHERE INVOICE_NUM=1001);
Advantech 135 Krishnamurthy
SELECT * FROM
TABLE(SELECT ITEM_DETAILS
FROM INVOICE
WHERE INVOICE_NUM=1001);
SELECT
I.INVOICE_NUM,
I.CUST_NAME,
LI.ITEM_NAME,
LI.ITEM_QTY,
LI.ITEM_PRICE
FROM INVOICE I,TABLE(I.ITEM_DETAILS) LI;
Now you can create a view for the above statement
Advantech 136 Krishnamurthy
CREATE VIEW INVOICE_ITEM
AS
SELECT
I.INVOICE_NUM,
I.CUST_NAME,
LI.ITEM_NAME,
LI.ITEM_QTY,
LI.ITEM_PRICE
FROM INVOICE I,TABLE(I.ITEM_DETAILS) LI;
Now we can query the view using item_name
SELECT * FROM INVOICE_ITEM
WHERE ITEM_NAME='80GB HDD';
To find total invoice amount for each customer
SELECT I.INVOICE_NUM,I.CUST_NAME,
SUM(LI.ITEM_QTY*LI.ITEM_PRICE) "Total Amount"
FROM INVOICE I,TABLE(I.ITEM_DETAILS) LI
GROUP BY I.INVOICE_NUM,I.CUST_NAME
Advantech 137 Krishnamurthy
Performing DML operation on nested table column
Inserting into nested table column
INSERT INTO THE(SELECT ITEM_DETAILS FROM INVOICE
WHERE INVOICE_NUM=1001)
VALUES('120GB HDD',2,6500);
Updating a nested table column
UPDATE TABLE(SELECT ITEM_DETAILS FROM INVOICE
WHERE INVOICE_NUM=1002)
SET ITEM_PRICE=5200,ITEM_QTY=4 WHERE ITEM_NAME='80GB
HDD';
Deleting a nested table row
DELETE FROM TABLE(SELECT ITEM_DETAILS FROM
INVOICE WHERE INVOICE_NUM=1002)
WHERE ITEM_NAME='KEYBOARD';
Advantech 138 Krishnamurthy
varray in database columns
CREATE TYPE HOBBIES_ARRAY AS VARRAY(3) OF VARCHAR2(15);
CREATE TABLE PERSON(
name VARCHAR2(12) PRIMARY KEY,
HOBBY HOBBIES_ARRAY);
INSERT INTO PERSON VALUES('PRAKASH',
HOBBIES_ARRAY('CRICKET','MOVIES','READING'))
INSERT INTO PERSON VALUES('GANESH',
HOBBIES_ARRAY('FOOTBALL','TENNIS','TV'));
SELECT * FROM PERSON;
SELECT * FROM TABLE(SELECT HOBBY
FROM PERSON WHERE NAME='PRAKASH');
SELECT P.NAME,H.*
FROM PERSON P,TABLE(P.HOBBY) H;
Advantech 139 Krishnamurthy
While updating we have to update entine collection
UPDATE PERSON SET HOBBY=HOBBIES_ARRAY('FOOTBALL')
WHERE NAME='PRAKASH';
When listed PRAKASH will be having only 'FOOTBALL' value
SELECT P.NAME,H.*
FROM PERSON P,TABLE(P.HOBBY) H;
SELECT P.NAME,H.*
FROM PERSON P,TABLE(P.HOBBY) H
WHERE COLUMN_VALUE='FOOTBALL';
Advantech 140 Krishnamurthy

You might also like