Sunteți pe pagina 1din 135

6.

1
CAPITULO VI
LENGUA1E DE PROGRAMACION PL/SQL DE ORACLE
6.1 Caractersticas de PL/SQL
Lenguaje de programacion, utilizado para accesar bases de
datos ORACLE.

Extiende las capacidades de SQL, agregando elementos
encontrados en los lenguajes de programacion procedurales:

Variables y tipos
Estructuras de control como: iI then else, ciclos
Procedimientos y Iunciones.

Basado en el lenguaje ADA: estructura de bloque, manejo de
excepciones, procedimientos, Iunciones, packages, etc.

Incorpora: encapsulamiento de datos, ocultamiento de
inIormacion, sobrecarga y manejo de excepciones.
6. 2
Arquitectura de ORACLE






Data
O / S
ORACLE 7
SQL
ORACLE Tools
6. 3
Herramientas de ORACLE


Herramientas de desarrollo
de aplicaciones

CASE* Dictionary
CASE* Designer
CASE* Generator
Oracle Graphics
Oracle Terminal
SQL* Plus
SQL* Forms
SQL* Menu
SQL* ReportWriter
SQL* TextRetrieval
Pro* (precompiladores)
Oracle Card
Aplicaciones
financieras

Oracle General Ledger
Oracle Purchasing
Oracle Payables
Oracle Assets
...
Aplicaciones de
Manufacturacin

Oracle Work in Process
Oracle Costing
Oracle Bill oI Materials
Oracle Engineering
Oracle Master Scheduling
Utilidades de Base de
Datos

SQL* DBA
Export / Import
SQL* Loader
Herramientas para el
soporte de decisiones

Easy* SQL
SQL* Calc
SQL* QMX
Data Query
SQL




PL / SQL
ORACLE server y
Diccionario de datos
Integrado
Herramientas de
Integracin de Productos

ORACLE Ior 1-2-3
ORACLE Ior dBASE
ORACLE Ior 4
th
Dimension
ORACLE Soluciones de
relicencia de valores
agregados

AI
CAD/CAM/CIM/CAE
Retail
Distribution
Project Management
...
Herramientas de
Automatizacin de oficinas

ORACLE* Mail
ORACLE* Alert
ORACLE Post Card
ORACLE Co Author
Productos de
Conectividad

SQL* Net
SQL* Connect
ORACLE Palm Link
6. 4

Uso de SQL por parte de una aplicacion.
6. 5
6.2 Motor PL/SQL
Ejecuta bloques y subprogramas PL/SQL.

El motor puede ser instalado en un servidor ORACLE o en
una herramienta de desarrollo de aplicaciones, tal como
SQL* Forms, SQL* Menu o SQL* ReportWriter.

PL/SQL puede residir en dos ambientes:
El servidor ORACLE
Herramientas de ORACLE
Bloque
PL/SQL
Bloque
PL/SQL
Procedural
Ejecutor
de sentencias
procedurales
SQL
Motor PL/SQL
Motor PL/SQL
6. 6





ORACLE
con PL/SQL
Servidor
Bloque PL/SQL
END_IF
ELSE
IF ... THEN
SQL
SQL
SQL
APLICACION
Servidor ORACLE con motor PL/SQL incluido.
6. 7


SQL` Forms
Bloque PL/SQL

DECLARE
Procedural
Procedural

BEGIN
Procedural
SQL
Procedural
SQL

END;
TRIGGER
Bloque PL/SQL

DECLARE
Procedural
Procedural

BEGIN
Procedural
SQL
Procedural
SQL

END;
E
J
E
C
U
T
O
R

D
E
S
E
N
T
E
N
C
I
A
S
P
R
O
C
E
D
U
R
A
L
E
S
Motor PL/SQL
Ejecutor de sentencias SQL
Servidor ORACLE
Motor PL/SQL en la herramienta SQL*Forms
6. 8

Maquina PL/SQL
Ejecutor de sentencias
procedurales
Ejecutor de
sentencias SQL
Servidor de base de datos ORACLE
DECLARE
v_StudentRecord studensROWTYPE;
v_Counter BINARY_INTEGER;
BEGIN
v_Counter : 7;

SELECT `
INTO v_StudentRecord
FROM students
WHERE id 10001;
END;
UPDATE classes
SET max_studetns 70
WHERE department HIS`
AND course 101;
Aplicacion Cliente
Datos se envan a travs de la red
El motor PL/SQL en el servidor
6. 9

Maquina PL/SQL
Ejecutor de sentencias
procedurales
Ejecutor de
sentencias SQL
Servidor de base de datos ORACLE
DECLARE
v_StudentRecord studensROWTYPE;
v_Counter BINARY_INTEGER;
BEGIN
v_Counter : 7;

SELECT `
INTO v_StudentRecord
FROM students
WHERE id 10001;
END;
UPDATE classes
SET max_studetns 70
WHERE department HIS`
AND course 101;
Aplicacion Cliente
Maquina PL/SQL
Ejecutor de sentencias
procedurales
El motor PL/SQL en el cliente
6. 10
6.3 Versiones de PL/SQL
Versiones de ORACLE y PL/SQL
Versin
Oracle
Versin
PL/SQL
Caractersticas agregadas o cambiadas
6 1.0 (Version Inicial)
7.0 2.0
Tipo de dato CHAR cambiado a longitud Iija.
Subprogramas (procedimientos, Iunciones,
paquetes y triggers).
Tipos de datos compuestos deIinidos por el
usuario (tablas y registros).
Comunicacion intersesion con los paquetes
DBMSPIPE y DBMSALERT.
Salida en SQL*Plus o SQL*DBA con el
paquete DBMSOUTPUT.
7.1 2.1
Subtipos deIinidos por el usuario.
Capacidad para Iunciones deIinidas por el
usuario en sentencias SQL.
PL/SQL dinamico con el paquete
DBMSSQL.
7.2 2.2
Variables tipo cursor.
Subtipos restringidos deIinidos por el usuario.
Capacidad para planear procesamiento batch
PL/SQL con el paquete DBMSJOB.
7.3 2.3
Mejoramiento de las variables tipo cursor
(habilidad para buscar en el servidor).
Archivos de I/O con el paquete UTLFILE.
Atributos de tablas y tablas de registros
PL/SQL.
Triggers almacenados en Iorma compilada.
6. 11
AL CONECTARSE A LA BASE DE DATOS:

Connected to:
Personal ORACLE7 Release 7.1.4.1.0 Production Release
PL/SQL Release 2.1.4.0.0-Production

6.4 Estructura de bloque

La unidad basica en cualquier programa PL/SQL es un
BLOQUE.

Existen varias clases distintas de bloques:

Bloques annimos

Bloques con nombre

Subprogramas

Triggers
6. 12

DECLARE



BEGIN



EXCEPTION



END;
Estructura de un bloque PL/SQL
6. 13
La estructura de un bloque considera:

Seccion de declaracion
Seccion ejecutable
Seccion de manejo de excepciones

La codificacin con PL/SQL considera:

Los bloques pueden contener subloques, los que
pueden aparecer donde quiera que una declaracion
ejecutable puede legalmente aparecer.

Las sentencias terminan con un punto y coma (;)

Los comentarios van precedidos de o rodeados por /* */

Los objetos declarados existen dentro de un cierto
alcance ("scope").

6. 14
6.5 Declaracin de tipos de datos y variables

A. Declaracin de variables PL/SQL

Se utiliza la seccion de declaracion
DECLARE




BEGIN




Seccion de declaracion de un bloque PL/SQL
6. 15
B. Tipos de Datos PL/SQL

REAL
INTEGER
SMALLINT
FLOAT
DECIMAL
NUMBER
BINARY_INTEGER
POSITIVE
NATURAL
CHAR
ROWID
LONG
VARCHAR
O
VARCHAR2
BOOLEAN
DATE
RAW
LONG RAW
Tipos Escalares
Tipos Compuestos
RECORD
TABLE
Tipos de datos PL/SQL
6. 16
C. Tipos de datos escalares
CHAR
VARCHAR2
NUMBER
BINARYINTEGER
BOOLEAN (TRUE, FALSE o NULL)
NUMBER, CHAR, VARCHAR2 y DATE se
comportan de la misma manera que sus
correspondientes tipos de datos en la base de datos.

D. Tipos de datos compuestos
TABLE ('Arreglo Unidimensional)
RECORD

E. Declaracin de variables escalares

Sintaxis:


Identificador CONSTANT] tipodedato NOT NULL] : expresinplsql];
6. 17
Ejemplos:


NUMBER/BINARYINTEGER


CHAR/VARCHAR2

DECLARE
Iirstname CHAR(20); ---- legal
lastname CHAR(20); ---- legal
cnt BINARYINTEGER;
renueve NUMBER(9,2);
secondsperday CONSTANT NUMBER : 60*60*24;
runningtotal BINARYINTEGER : 0;
midinitial CHAR;
lastname VARCHAR2 (10) NOT NULL : PEEBLES`;
companyname CONSTANT VARCHAR2(12) : ORACLE`;
6. 18

DATE



BOOLEAN

F. Declaracin de variables compuestas

1. TABLE
Sintaxis:
anniversary DATE : `05 JUL 89`;
projectcompletion DATE;
nextcheckup DATE NOT NULL : `28 DEC 92`;
overbudget BOOLEAN NOT NULL : FALSE;
available BOOLEAN : NULL;
TYPE nombretipo IS TABLE OF
tipocolumna [ tabla.columnaTYPE } |NOT NULL|
INDEX BY BINARYINTEGER;
Identificador nombretipo,
6. 19
TYPE nombretipo IS RECORD OF
(nombrecampo1 tipocampo , tabla.columnaTYPE} |NOT NULL|,
nombrecampo2 tipocampo , tabla.columnaTYPE } |NOT NULL|,
...);
identificador nombretipo,
Ejemplo:

Nota:
enametab representa una tabla
ReIerencias se hacen mediante: enametab(i)

2. RECORD

Sintaxis:

DECLARE
TYPE enametabtype IS TABLE OF VARCHAR2 (10)
INDEX BY BINARYINTEGER;
enametab enametabtype;
6. 20
DECLARE
booksprinted NUMBER(6);
bookssold books.printedTYPE;
maidenname emp.enameTYPE;
DECLARE
deptrow deptROWTYPE;
Ejemplo:








G. Atributos TYPE y ROWTYPE

Ejemplo: atributo TYPE:

Ejemplo: atributo ROWTYPE:


DECLARE
TYPE deptrectype IS RECORD OF
(deptno NUMBER(2) NOT NULL,
dname dept.dnameTYPE,
loc dept.locTYPE);
deptrec deptrectype;
6. 21
variableplsql : expresionplsql,
Nombretablaplsql (valorclaveprimaria) : expresionplsql,
nombreregistro.nombrecampo : expresionplsql,
6.6 Asignacin y conversin de tipos

A. Se asignan valores a variables compuestas y escalares.

Sintaxis:

a) Asignacin escalar



b) Asignacin de tablas

c) Asignacin de registros

6. 22
Ejemplo:


B. Conversin de tipos de datos:
PL/SQL trata automaticamente de convertir los tipos de
datos, si el tipo de dato esperado no es utilizado.
DECLARE
TYPE deptrectype IS RECORD
(deptno NUMBER(2) NOT NULL,
dname dept.dnameTYPE);
TYPE enametabtype IS TABLE OF CHAR(10)
INDEX BY BINARYINTEGER;
deptrec1 deptrectype;
deptrec2 deptrectype;
enametab enametabtype;
cnt BINARYINTEGER;
overbudget BOOLEAN;
lastname VARCHAR2(10);
BEGIN
cnt : cnt 1;
overbudget : TRUE;
lastname : JONES`;
enametab(3) : lastname;
deptrec1 : deptrec2;
END;
6. 23
6.7 Alcance de las variables y constantes
DECLARE
creditlimit CONSTANT NUMBER (6,2) : 2000;
account NUMBER;

BEGIN






SUB-BLOQUE 1

DECLARE
account CHAR(10);
new_balance NUMBER(9,2);

BEGIN




END;
new_balance
account credit_limt
SUB-BLOQUE 2

DECLARE
old_balance NUMBER(9,2);

BEGIN



END;
old_balance account credit_limt
account credit_limt
6. 24
6.8 Sentencias SQL dentro de PL/SQL
INSERT
UPDATE
DELETE
SELECT INTO

Seccion ejecutable de un bloque

BEGIN



EXCEPTION



END;
6. 25
Debe considerarse lo siguiente:
La sintaxis completa de ORACLE es soportada para
estas sentencias.
Una variable PL/SQL puede ser colocada en cualquier
lugar donde legalmente pueda ser colocada una
constante.
Un identiIicador primero es chequeado para ver si es
una columna en la base de datos. Si no lo es, se asume
que es un identiIicador PL/SQL.
Estas sentencias no pueden aparecer como parte de una
expresion.
No son soportadas sentencias DDL y algunas DCL de
SQL.
A. INSERT
DECLARE
mysal NUMBER(7,2) : 3040.55;
myename CHAR(25) : WANDA`;
myhiredate DATE : 08-SEP-88`;

BEGIN
INSERT INTO emp (empno, ename, job, hiredate, sal, deptno)
VALUES (2741, myename, CHAUFFEUR`, myhiredate, mysal, 20);
END;
6. 26
B. UPDATE

C. DELETE
DECLARE
maxallowed CONSTANT NUMBER : 5000;
goodcust CHAR(8) : VIP`;

BEGIN
UPDATE accounts SET creditlimit maxallowed
WHERE status EMPLOYEE` or status goodcust;
END;
DECLARE
yearvar NUMBER : 1800;

BEGIN
DELETE FROM invention
WHERE year yearvar;
END;
6. 27
D. SELECT INTO






Sintaxis SELECT:

Ejemplo SELECT:
SELECT col1, col2, ... INTO var1, var2, ...
FROM nombretabla WHERE ...
DECLARE
partname parts.nameTYPE;
numinstock parts.numTYPE;
BEGIN
SELECT name, num INTO partname, numinstock
FROM parts WHERE partid 624;



END;
manipulacion de los datos recuperados aqui
APLICACION
VAR1
VAR2
VAR3
SELECT
INTO
7844 TURNER 1500
7654 MARTIN 1250

EMPNO ENAME SAL
EMP
6. 28
6.9 Referencias a funciones SQL incorporadas

Es posible reIerenciar a las Iunciones incorporadas, tanto en
sentencias SQL como en sentencias procedurales.

A. Referencia a funciones en sentencias SQL

Numeric (por ejemplo: SQRT, ROUND, POWER)
Character (por ejemplo: LENGTH, UPPER, SUBSTR)
Date (por ejemplo: ADDMONTHS, MONTHSBETWEEN)
Group (por ejemplo: AVG, MAX, COUNT)
Conversion (Ejemplos: TOCHAR, TODATE, TONUMBER)
Miscelaneas (Ejemplos: LEAST, NVL, DECODE)

Ejemplo: Uso de funciones en una sentencia DML

INSERT INTO phonebox (lastname) VALUES
(UPPER (mylastname));

6. 29
B. Referencia a funciones en sentencias procedurales
Funciones SQL listadas arriba, excepto el DECODE y
las Iunciones de grupo.
Reporte de errores (por ejemplo: SQLCODE,
SQLERRM)
Ejemplo : Uso de funciones en una sentencia de asignacin
X : SQRT(y);
lastname : UPPER(lastname);
agediII : MONTHSBETWEEN (birthday1, birthday2)/12;

6.10 Sentencias de control de cdigo condicional e iterativo

BEGIN


EXCEPTION



END;
Seccion ejecutable
6. 30
A. Ejecucin de comparaciones lgicas

Comparaciones lgicas:

Consisten de expresiones simples o complejas
separadas por operadores relacionales.
Los resultados son siempre, TRUE, FALSE o NULL.

Comparaciones nulas:

Cualquier cosa comparada con NULL, resulta en un
valor NULL.
Un NULL en una expresion se evalua a NULL
(excepto en concatenaciones).

Ejemplos:
5 NULL - - evalua a NULL
PL/` , , NULL , , SQL` -- evalua a PL/ SQL
6. 31
Tablas de verdad de los operadores lgicos
B. Sentencia IF-THEN-ELSE
Sintaxis:
TRUE FALSE NULL

T

F

N

F

F

F

N

F

N

TRUE
FALSE
NULL
AND
TRUE FALSE NULL

T

T

T

T

F

N

T

N

N

TRUE
FALSE
NULL
OR
F
T
N

NOT
TRUE
FALSE
NULL
IF condicion~ THEN
secuencia de sentencias~
|ELSIF condicion~ THEN
secuencia de sentencias~|
-- ELSEIF`s pueden ser repetidos
|ELSE
secuencia de sentencias~ |
END IF;
6. 32
Ejemplo de la sentencia IF-THEN-ELSE:
DECLARE
numjobs NUMBER(7);

BEGIN
SELECT COUNT(*) INTO numjobs FROM auditions
WHERE actorid &&actorid AND calledback YES`;

IF numjobs ~ 90 THEN
UPDATE actor SET actorrating OSCAR time`
WHERE actorid &&actorid;
ELSIF numjobs ~ 75 THEN
UPDATE actor SET actorrating Daytime soaps`
WHERE actorid &&actorid;
ELSE
UPDATE actor SET actorrating Waiter`
WHERE actorid &&actorid;
END IF;

COMMIT;
END;
6. 33
C. Sentencias de ciclo

4 Tipos de Loops:
Ciclo simple
Ciclo FOR numerico
Ciclo WHILE
Ciclo FOR de cursores

1. Ciclo simple

Sintaxis de un ciclo simple:


Sintaxis de Exit:

LOOP
secuencia de sentencias~
END LOOP; -- a veces llamado ciclo inIinito
EXIT |when CONDICION~ |;
6. 34
Ejemplos:
DECLARE
ctr NUMBER(3) : 0;
BEGIN
LOOP
INSERT INTO LOG VALUES
(ctr, ITERACION COMPLETA`);
ctr : ctr 1;
IF ctr 500 THEN
EXIT;
END IF;
END LOOP;
END;
DECLARE
ctr NUMBER(3) : 0;
BEGIN
LOOP
UPDATE TABLE1 SET comment ACTUALIZADO`
WHERE countcol ctr;
ctr : ctr 1;
EXIT WHEN ctr 100;
END LOOP;
END;
6. 35
2. Ciclo FOR numrico
Sintaxis:

Ejemplos:

FOR indice~ IN |REVERSE| integer~ .. integer~ LOOP
secuencia de sentencias~
END LOOP;
BEGIN
FOR i IN 1..500 LOOP
INSERT INTO temp (col1, message)
VALUES (i, No me dormire en clases`);
END LOOP;
END;
DECLARE
myindex CHAR(20) : Fetuccini AlIredo`;
BEGIN
FOR myindex IN REVERSE 21..30 LOOP
/* redeclaracion de myindex*/
INSERT INTO temp (col1)
VALUES (myindex);
/*Inserta los numeros 30 a 21*/
END LOOP;
END;
6. 36

En el cliclo FOR numrico, el ndice utilizado es:
Implicitamente de tipo NUMBER.
DeIinido solo dentro del loop.
Su valor puede ser reIerenciado en una expresion,
pero un nuevo valor no puede ser asignado al indice
dentro del loop.

3. Ciclo WHILE
Sintaxis:
...
FOR i IN 1..256 LOOP
x : x i; --legal
i : i 5; -- ilegal
END LOOP;
...
WHILE condicion~ LOOP
secuencia de sentencias~
END LOOP;
6. 37
Ejemplo:


4. Sentencia GO TO

Sintaxis:


DECLARE
ctr NUMBER(3) : 0;
BEGIN
WHILE ctr 500 LOOP
INSERT INTO temp (col1, message)
VALUES (ctr, Bien, podria dormir solo un poquito`);
ctr : ctr 1;
END LOOP;
END;
nombrerotulo~~ x : x 1; -- un rotulo de sentencia
GO TO nombrerotulo; -- transIiere el control a x: x 1;
6. 38
Legal Ilegal






Referencia a rtulos de sentencia:
Los rotulos pueden rotular a cualquier sentencia.
Ademas de su uso en sentencias asociadas a un GO TO, los
rotulos se pueden usar en bloques y ciclos.
Los rotulos en un bloque permiten reIerenciar objetos
declarados, que podrian de otra manera no ser visibles
debido a las reglas de alcance.
Sintaxis:
dinner~~ GO TO yourbrothers;
x : x 1; IF a ~ b THEN
y : y x; b : b c;
IF a ~ b THEN yourbrothers~~
b : b c; x : x 1;
GO TO dinner; END IF;
END IF;
nombrerotulo~~
|DECLARE
-- las declaraciones van aqui|
BEGIN
-- sentencias ejecutables van aqui
|EXCEPTION
-- manejo de excepciones aqui|
END nombrerotulo; --debe incluir el nombre del rotulo
6. 39

Ejemplo:

Ejemplo:
outerblock~~
DECLARE
n NUMBER;
BEGIN
n : 5;
/* Comienzo de un sub bloque */
DECLARE
x NUMBER : 10;
n CHAR(10) : Quince`;
BEGIN
INSERT INTO temp (col1, col2, message)
VALUES (outerblock.n, x, n);
COMMIT;
END; /*Iin del sub bloque */
END outerblock
sample~~
DECLARE
deptno NUMBER : 20;
BEGIN
UPDATE emp SET sal sal * 1.1;
WHERE deptno sample.deptno;
COMMIT;
END sample;
6. 40
Ejemplo:

Ejemplo:

computeloop~~
FOR i IN 1..10 LOOP
sentencias~
DECLARE
i NUMBER : 0;
BEGIN
INSERT INTO temp (col1, col2, message)
VALUES (i, computeloop.i, COMPLETE`);
END;
END LOOP computeloop; -- debe incluir el nombre del loop aqui
...
loopexterno~~ WHILE a ~ b LOOP
b : b 1;
loopinterno~~ WHILE b ~ c LOOP
c : c 2;
EXIT loopexterno WHEN c ~ 200;
END LOOP loopinterno;
END LOOP loopexterno;
...
6. 41
6.11 Cursores
A. Conceptos

Toda sentencia del DML SQL procesada por PL/SQL tiene
un cursor asociado.
DECLARE




BEGIN



Seccion de declaracion y seccion ejecutable al crear un cursor
6. 42
Sentencias SQL asociadas a un cursor:

INSERT
UPDATE
DELETE
SELECT INTO
COMMIT
ROLLBACK


B. Tipos de cursor

Tipo Descripcin
Explcito Sentencias SELECT con
multiples Iilas en el resultado.
Implcito Todas las sentencias INSERT
Todas las sentencias UPDATE
Todas las sentencias DELETE
Sentencias SELECT .. INTO


6. 43

Obtiene una fila
Cursor
.
.
.
Procesa una fila
.
.
.
Continuar hasta que est
vaco
.
.
.
Cursor
Declaracion y uso de cursores explicitos
6. 44
El conjunto de Iilas retornadas por una consulta puede
consistir de cero, una o mas Iilas, dependiendo del numero de
Iilas que satisIagan la condicion de busqueda.
Cuando una consulta retorna multiples Iilas, un cursor puede
ser deIinido explicitamente para:
Procesar mas alla de la primera Iila recuperada por la
consulta.
Mantener la pista de cual es la Iila que esta actualmente
siendo procesada.

C. Pasos para declarar y usar un cursor:
1. Declarar el cursor
2. Abrir el cursor
3. Sacar los datos desde el cursor
4. Cerrar el cursor

1.) Declaracin de un cursor para asociar su nombre
con una sentencia SELECT

Sintaxis de la declaracin del cursor:
DECLARE
CURSOR nombrecursor~
IS sentenciaselectregular ~;
6. 45
Ejemplo: Declaracin de un CURSOR

2.) Abrir el cursor para procesar la sentencia SELECT y
almacenar las filas retornadas en el cursor

Sintaxis para abrir el cursor:

3.) Extraer los datos desde el cursor y almacenarlos en
las variables especificadas

Sintaxis para el Fetch a los datos:
DECLARE
x NUMBER(7,2);
total NUMBER(5);
limiteinIeriorsalario CONSTANT NUMBER(4) : 1200;
CURSOR c1 IS SELECT ename FROM emp
WHERE sal ~ limiteinIeriorsalario;
BEGIN. . .
OPEN nombrecursor~;
FETCH nombrecursor~ INTO var1, var2, . . .~;
6. 46
4.) Cerrar el cursor para liberar el recurso
Sintaxis para cerrar el cursor:

D. Referencia a los atributos de los cursores explcitos:
NOTFOUND, FOUND, ROWCOUNT, ISOPEN

1.) NOTFOUND se evalua en TRUE, si el FETCH
previo no retorna Iilas.

Ejemplo NOTFOUND:

2.) FOUND se evalua en TRUE, si el FETCH
previo retorna una Iila

Ejemplo FOUND:
CLOSE nombrecursor~
LOOP
FETCH mycursor INTO myename, mysal;
EXIT WHEN mycursorNOTFOUND;
-- procesamiento de datos aqui
END LOOP;
FETCH mycursor INTO myename, mysal;
WHILE mycursorFOUND LOOP
-- procesamiento de datos aqui
FETCH mycursor INTO myename, mysal;
END LOOP;

6. 47
3.) ROWCOUNT se evalua al numero total de Iilas
obtenidas hasta el momento.

Ejemplo ROWCOUNT:

4.) ISOPEN se evalua en TRUE, si el cursor asociado
esta abierto.

Ejemplo ISOPEN:
LOOP
FETCH mycursor INTO myename, mysal;
EXIT WHEN (mycursorNOTFOUND)
OR (mycursorROWCOUNT ~ 10);
-- procesamiento de datos aqui
END LOOP;
IF mycursorISOPEN THEN
FETCH mycursor INTO myename, mysal;
ELSE
OPEN mycursor;
END IF;
6. 48
Ejemplo:


DECLARE
sallimit NUMBER(4) : 0
myename emp.enameTYPE;
mysal emp.salTYPE;
CURSOR mycursor IS SELECT ename, sal FROM emp
WHERE sal ~ sallimit;
BEGIN
sallimit : 1200;
OPEN mycursor; -- use 1200 como sallimit
LOOP
FETCH mycursor INTO myename, mysal;
EXIT WHEN mycursorNOTFOUND; -- nada retornado
INSERT INTO newtable VALUES (myename, mysal);
END LOOP;
CLOSE mycursor;
COMMIT;
END;
6. 49

Ejemplo: Reapertura de un cursor
DECLARE
totalbonus NUMBER(8,2) : 0;
minsal emp.salTYPE : 1000; -- Suposicion inicial
bonusamt emp.salTYPE;
CURSOR bonus IS
SELECT sal * .10 FROM emp WHERE sal ~ minsal;
BEGIN
OPEN bonus; -- usa el valor de minsal de 1000
LOOP
FETCH bonus INTO bonusamt;
EXIT WHEN bonusNOTFOUND;
totalbonus : totalbonus bonusamt;
IF totalbonus ~ 2000 THEN
/* incrementar el minimo y tratar de nuevo */
minsal : minsal 500;
totalbonus : 0 --- resetear el total
CLOSE bonus;
OPEN bonus; -- re abrir con nuevo minsal
END IF;
END LOOP;
-- se podria querer almacenar minsal en algun lado
END;
6. 50
E. Referencia a la fila actual del cursor
Sintaxis:

Ejemplo:
WHERE CURRENT OF nombrecursor~
DECLARE
CURSOR mycur IS SELECT ename, sal FROM emp
FOR UPDATE oI sal;
empname emp.enameTYPE;
salary emp.salTYPE;
BEGIN
OPEN mycur;
LOOP
FETCH mycur INTO empname, salary;
EXIT WHEN mycurNOTFOUND;
IF salary ~ 3000 THEN
DELETE FROM emp WHERE CURRENT OF mycur;
END IF;
. . .
END LOOP;
6. 51
F. Ciclo FOR para referenciar a un cursor:
Permite la especiIicacion de una secuencia de sentencias, para
ser repetida, una vez por cada Iila que sea retornada por el
cursor.
Sintaxis ciclo FOR para el cursor:

Esta clase de ciclo FOR considera:
Los ciclos FOR de cursores son similares a los ciclos FOR
numericos.
Los ciclos FOR especiIican un conjunto de Iilas de una
tabla, usando el nombre del cursor. Los ciclos FOR
numericos especiIican un rango de enteros.
Un registro de un ciclo FOR para el cursor, toma los
valores de cada Iila. Un indice de un ciclo FOR numerico,
toma cada valor en el rango.
nombrerecord es implicitamente declarado como:

Para reIerenciar a un elemento del registro, se usa la
notacion nombrerecord.nombrecolumna.
FOR nombrerecord~ IN nombrecursor~ LOOP
-- sentencias para ser repetidas, aqui
END LOOP;
nombrerecord nombrecursorROWTYPE;
6. 52
G. Modelo conceptual del ciclo FOR para el cursor:
Cuando es iniciado el ciclo, se ejecuta un OPEN
nombrecursor implicito.
Por cada Iila que satisIace la consulta asociada al
cursor, se ejecuta un FETCH implicito hacia los
componentes de nombrerecord.
Cuando no existen mas Iilas que retornar con FETCH,
se ejecuta un CLOSE nombrecursor implicito y se
sale del ciclo.
Ejemplo:
DECLARE
sallimit NUMBER(4) : 0;
totalsal NUMBER(9,2) : 0;
CURSOR mycursor IS SELECT ename, sal FROM emp
WHERE sal ~ sallimit;
BEGIN
sallimit : 1200;
-- OPEN implicito aqui
FOR cursorrow IN mycursor LOOP
-- se hace un implicito FETCH aqui
INSERT INTO newtable
VALUES(cursorrow.ename, cursorrow.sal);
totalsal : totalsal cursorrow.sal;
END LOOP; -- se hace un close implicito aqui
-- almacena totalsal en tabla temp
INSERT INTO temp (COL1, MESSAGE)
VALUES (totalsal, Salario total`);
COMMIT;
END;
6. 53
Ejemplo: Carga de datos dentro de una tabla PL/SQL,
mediante un ciclo FOR para cursor:
DECLARE
TYPE enametabtype IS TABLE OF emp.enameTYPE
INDEX BY BINARY INTEGER;
TYPE saltabtype IS TABLE OF emp.salTYPE
INDEX BY BINARY INTEGER;
enametab enametabtype;
saltab saltabtype;
i BINARYINTEGER : 0;
CURSOR empcur IS SELECT ename, sal FROM emp;
BEGIN
-- cargar nombres de empleados y salarios dentro
-- de las tablas PL/SQL.
FOR emprec IN empcur LOOP
i : i 1;
enametab(i) : emprec.ename;
saltab(i) : emprec.sal;
END LOOP;
-- procesos de tablas PL/SQL
. . .
END;
6. 54
H. Declaracin explcita de parmetros para los
cursores
Sintaxis:

Ejemplo:

Es equivalente a:

DECLARE
CURSOR nombrecursor~ |(nombreparametro tipoparametro)|
IS sentencia select regular ~;
DECLARE
CURSOR empcur (salvalue NUMBER) IS
SELECT ename FROM emp WHERE sal ~ salvalue;
BEGIN
OPEN empcur (1200);
. . .
END;
DECLARE
salvalue NUMBER;
CURSOR empcur IS
SELECT ename FROM emp WHERE sal ~ salvalue;
BEGIN
salvalue : 1200;
OPEN empcur;
. . .
END;
6. 55
I. Referencia a los atributos de los cursores implcitos:
SQLNOTFOUND, SQLFOUND,
SQLROWCOUNT, SQLISOPEN.

1.) SQLNOTFOUND se evalua a TRUE, si la sentencia SQL
mas recientemente ejecutada, no aIecta a ninguna tupla.
Ejemplo de SQLNOTFOUND:
2.) SQLFOUND se evalua a TRUE, si la sentencia SQL
mas recientemente ejecutada aIecta a una o mas tuplas.
3.) SQLROWCOUNT se evalua al numero de tuplas
aIectadas por una sentencia DELETE o UPDATE, Al
numero de tuplas INSERTadas, o al numero de Iilas
recuperadas por un SELECT INTO.
Ejemplo de SQLROWCOUNT:

4.) SQLISOPEN siempre se evalua a FALSE.
DELETE FROM baseballteam WHERE battingavg .100;
IF SQLROWCOUNT ~ 5 THEN
INSERT INTO temp (message)
VALUES (Tu equipo necesita ayuda`);
END IF;
UPDATE emp SET sal sal*10.0 WHERE ename WARD`;
IF SQLNOTFOUND THEN -- WARD no Iue encontrado
INSERT INTO emp(empno, ename, sal) VALUES
(1234,`WARD`,99999);
END IF;
6. 56
6.12 Manejo de excepciones
A. CONCEPTOS
Se utiliza la seccion de excepciones

Seccin de excepciones
BEGIN
EXCEPTION
END;
6. 57
En PL/SQL, los errores son llamados excepciones.
Cuando se levanta una excepcion, el proceso salta a los
manejadores de excepciones.
Un manejador de excepciones es una secuencia de sentencias
a ser procesadas cuando una cierta excepcion ocurre.
Cuando el manejador de excepcion esta completado, termina
el procesamiento del bloque.
B. Tipos de excepciones
Excepciones internas pre definidas:
Corresponden aproximadamente a 20 errores comunes en
ORACLE.
Son levantadas automaticamente por PL/SQL, en
respuesta a un error ORACLE.
Excepciones definidas por el usuario:
Deben ser declaradas.
Deben ser levantadas explicitamente.
Declaracin del manejador de excepciones:
Sintaxis:
WHEN <nombre_excepcin> OR <nombre_excepcin> ....] THEN
<secuencia de sentencias>
. . .
WHEN OTHERS THEN --si es usado, debe ser el ltimo
manejador
<secuencia de sentencias> ]
6. 58
Ejemplo:
DECLARE
employee_num emp.empnoTYPE;

BEGIN
SELECT empno INTO employee_num FROM emp
WHERE ename BLAKE`;
INSERT INTO temp (col1, message)
VALUES (employee_num, Blake``s employee number.`);
DELETE FROM emp WHERE ename BLAKE`;

EXCEPTION
WHEN NO_DATA_FOUND THEN
ROLLBACK;
INSERT INTO temp (message)
VALUES (BLAKE no encontrado`);
COMMIT;
WHEN TOO_MANY_ROWS THEN
ROLLBACK;
INSERT INTO temp (message)
VALUES (Ms de un BLAKE encontrado`);
COMMIT;
WHEN OTHERS THEN
ROLLBACK;
END;
6. 59
Declaracin de excepciones definidas por el usuario:
Las excepciones pre deIinidas por el usuario se deIinen y
levantan explicitamente.
Ejemplos:

RAISE excepcion (llamado a la excepcion predeIinida):

Debe considerarse:
Una vez que la excepcion es levantada manualmente,
se trata exactamente como si Iuese una excepcion
interna predeIinida.
El alcance de la declaracion de excepciones es igual
que con las variables.
Una excepcion predeIinida por el usuario es chequeada
manualmente y levantada si es apropiado.
DECLARE
x NUMBER;
myexception EXCEPTION; -- un nuevo tipo de objeto
. . .
RAISE myexception;
6. 60
Ejemplo:
DECLARE
myename emp.enameTYPE : BLAKE`;
assignedprojects NUMBER;
tooIewprojects EXCEPTION;

BEGIN
-- obtiene los numeros de proyectos asignados a BLAKE
. . .
IF assignedprojects 3 THEN
RAISE tooIewprojects;
END IF;

EXCEPTION -- comienzo de los manejadores de excepciones
WHEN tooIewprojects THEN
INSERT INTO temp
VALUES (myename, assignedprojects,
MENOS DE 3 PROYECTOS!`);
COMMIT;
. . .
END;
6. 61
C. Propagacin de Excepciones
Pasos en la propagacin:
1. El bloque actual es buscado para un manejador. Si no lo
encuentra, ir al paso 2.

2. Si se encuentra un bloque que encierra, este es buscado
para un manejador.

3. Se repiten los pasos 1 y 2 hasta que no se encuentren
mas bloques que encierran, o hasta que se encuentre un
manejador.
Si no existen mas bloques que encierran, la
excepcion es pasada de vuelta al ambiente que la
llama (SQL* Plus, SQL* Forms, un programa pre
compilado, etc.).
Si se encuentra un manejador, este es ejecutado.
Cuando esto se hace, el bloque en el cual se
encontro el manejador es terminado y el control es
pasado al bloque que encierra (si existe), o al
ambiente (si no existe el bloque).
6. 62
Ejemplo:


BEGIN
IF X 1 THEN
RAISE A;
ELSEIF X 2 THEN
RAISE B;
ELSE
RAISE C;

EXCEPTION
WHEN A THEN
. . .
END;

BEGIN
. . .
_________
_________
_________
EXCEPTION
WHEN B THEN
. . .
END;
Exception A es
manejada localmente y
la ejecucin se reasume
en el bloque externo
6. 63
Ejemplo:
BEGIN
IF X 1 THEN
RAISE A;
ELSIF X 2 THEN
RAISE B;
ELSE
RAISE C;

EXCEPTION
WHEN A THEN
. . .
END;

BEGIN
. . .
EXCEPTION
WHEN B THEN
. . .
END;
Excepcin B es manejada
y el control es pasado de
vuelta al ambiente.
Excepcin B se propaga
al primer bloque externo
con un manejador
apropiado
6. 64
Ejemplo:

EXCEPTION
WHEN B THEN
. . .
END;
BEGIN
. . .
La excepcin C no tiene
manejador y resultar en
una excepcin no manejada
en tiempo de ejecucin.

BEGIN
IF X 1 THEN
RAISE A;
ELSEIF X 2 THEN
RAISE B;
ELSE
RAISE C;

EXCEPTION
WHEN A THEN
. . .
END;
6. 65
Otros usos del RAISE:

Esta sentencia re levanta la excepcion actual (como si
estuviera siendo propagada).

Sintaxis:


Es necesario tener en cuenta:
RAISE solo puede ser usado en un manejador de
excepciones.

D. Excepciones internas predefinidas

Cualquier error ORACLE levanta automaticamente una
excepcion; algunos de los errores mas comunes tienen
nombres.
RAISE;
6. 66
Ejemplos:
TOO_MANY_ROWS (ORA-01427)
--- un SELECT de unica Iila, retorno mas de una Iila

NO_DATA_FOUND (ORA-01403)
--- un SELECT de unica Iila, no retorno datos

INVALID_CURSOR (ORA-01001)
--- Ocurrio una operacion ilegal con el cursor

VALUE_ERROR (ORA-06502)
--- Ocurrio un error aritmetico, de conversion, truncamiento o de restriccion.

INVALID_NUMBER (ORA-01722)
--- Fallo la conversion de un string de caracteres a un numero en una sentencia SQL.

ZERO_DIVIDE (ORA-01476)
--- Intento de dividir por cero

DUP_VAL_ON_INDEX (ORA-00001)
--- Intento de insertar un valor duplicado dentro de una columna, la que tiene un
indice asociado que permite valores unicos en la columna.

CURSOR_ALREADY_OPEN (ORA-06511)
--- Intento de abrir un cursor ya abierto
6. 67
E. Pragma EXCEPTION_INIT
Las excepciones solo pueden ser manejadas por el nombre y
no a traves del numero de error ORACLE.

Con el pragma EXCEPTIONINIT, se puede dar un nombre
a un error particular de ORACLE.

Esto da la capacidad de atrapar un error especiIico, en lugar
de hacerlo via un manejador OTHERS.

Sintaxis:


Ejemplo:

PRAGMA EXCEPTION_INIT (nombreexcepciondeIinidaporelusuario~,
numeroerrorORACLE ~);
DECLARE
deadlockdetected EXCEPTION;
PRAGMA EXCEPTIONINIT (deadlockdetected, -60);
6. 68
Ejemplo:
Se levantara la excepcion deIinida por un usuario
e_MissingNull si se encuentra el error 'ORA-1400: columna
obligatoria NOT NULL Ialta o es NULL durante la
insercion en tiempo de ejecucion.

DECLARE
e_MissingNull EXCEPTION;
PRAGMA EXCEPTION_INIT (e_MissingNull, -1400);
BEGIN
INSERT INTO students (id) VALUES (NULL);
EXCEPTION
WHEN e_MissingNull then
INSERT INTO log_table (info) VALUES (ORA-1400 ocurre`);
END;

F. Funcin RAISE_APLICATION_ERROR

La Iuncion RAISEAPLICATIONERROR permite al
programador, crear sus propios mensajes de error.

Los errores deIinidos por el usuario son pasados Iuera del
bloque, de la misma Iorma que los errores de Oracle.
6. 69
La sintaxis de RAISEAPPLICATIONERROR es:

RAISEAPPLICATIONERROR(numero de error,
mensaje de error, |guarda errores|);

Donde:

nmero de error: parametro entre 20.000 y 20.999
mensaje de error: texto asociado con este error
guarda errores: un valor booleano opcional.
Si es TRUE, el nuevo error es agregado a la lista de
errores ya levantados (si existe una).
Si es FALSE, que es el valor por deIecto, el nuevo error
remplazara la actual lista de errores.

Ejemplo:
El siguiente procedimiento chequea si existe suIiciente
espacio en una sala de clase antes de incorporar a un nuevo
estudiante.

6. 70
CREATE OR REPLACE PROCEDURE Register (
/` Registra al estudiante identificado por el parmetro p_StudentID, en la
clase identificada por los parmetros p_Department y p_Course. Antes de
llamar a ClassPackage.AddStudent, el cual realmente agrega el estudiante a
la clase, este procedimiento verifica que exista suficiente espacio en una sala
de clase, y que la clase existe. `/
p_StudentID IN students.idTYPE,
p_Department IN classes.departmentTYPE,
p_Course IN classes.courseTYPE) AS

v_CurrentStudents NUMBER; -- Nmero actual de estudiantes en la clase
v_MaxStudents NUMBER; -- Nmero mximo de estudiantes en la clase
BEGIN
/` Determina el nmero actual de estudiantes registrados, y el nmero mximo
de estudiantes permitidos para registrarse. `/
SELECT current_students, max_students
INTO v_CurrentStudents, v_maxStudents
FROM classes
WHERE course p_Course
AND department p_Department;

/`Asegurarse de que existe suficiente espacio para este estudiante adicional`/
IF v_CurrentStudents + 1 > v_MaxStudents THEN
RAISE_APPLICATION_ERROR (-20000, No puede agregar ms estudiantes a`
[ [p_Department [ [ [ [ p_Course);
END IF;
/`Agrega el estudiante a la clase. `/
ClassPackage.AddStudent (p_StudentID, p_Department, p_Course);
. . .
6. 71
EXCEPTION
WHEN NO_DATA_FOUND THEN
/` La informacin de la clase pasada a este procedimiento no existe. Levantar un
error para que el programa que llam conozca esto `/
RAISE_APPLICATION_ERROR(-20001, p_Department [ [ [ [
p_Course [ [ no existe!`);
END Register;


Resultados del llamado al procedimiento Register



6. 72
G. Referencias a funciones de reporte de errores
Las funciones SQLCODE y SQLERRM:
Proveen inIormacion acerca de los errores actualmente
manejados.
Son especialmente utiles en el manejador OTHERS.

SQLCODE:
Retorna el numero de error ORACLE de la excepcion,
o 1 si Iue una excepcion deIinida por el usuario.

SQLERRM:
Retorna el mensaje de error ORACLE asociado con el
valor actual de SQLCODE.
Tambien puede usar cualquier numero de error
ORACLE, como un argumento.

Debe tenerse en cuenta:
Si no existe una excepcion activa...
SQLCODE 0
SQLERRM normal, succesIull completion.
SQLCODE y SQLERRM no pueden ser usados dentro
de una sentencia SQL.
6. 73
Ejemplo:
DECLARE
sqlcodeval NUMBER;
sqlerrmval CHAR(55);
BEGIN
. . .
EXCEPTION
WHEN OTHERS THEN
sqlcodeval : SQLCODE;
-- No se puede insertar directamente SQLCODE.

sqlerrmval : SUBSTR(SQLERRM, 1,55);
-- No se puede insertar directamente SQLERRM.
-- Tambien, SUBSTR debe ser usado para asegurarse de
-- que el string retornado cabe dentro de la variable objetivo.

INSERT INTO temp (col1, message)
VALUES (sqlcodeval, sqlerrmval);
END;
6. 74
6.13 Subprogramas Locales: Procedure y Functions

6.13.1 Conceptos

Los subprogramas:

Proveen extensibilidad

Proveen modularidad

Promueven la reusabilidad

Promueven la mantenibilidad

Ayudan a la abstraccion

6. 75



DECLARE
. . .
PROCEDURE . . . IS
BEGIN

EXCEPTION]

END;
. . .
BEGIN
. . .
Procedure_name . . . ;
. . .
Un subprograma local dentro de un bloque PL/SQL
6. 76
6.13.2 Procedimientos

Seccion de declaracion, seccion ejecutable y seccion
de manejo de excepciones de un procedimiento.




PROCEDURE ... IS



BEGIN



EXCEPTION]



END;
6. 77
Sintaxis Cuerpo del procedimiento:

donde: parametro representa lo siguiente:
nombreparametro modo tipo de dato |: value|

Sintaxis Llamado a un procedimiento:

Los procedimientos PL/SQL son especiIicos a ORACLE7 y
ORACLE 8.

PROCEDURE nombreprocedimiento | (parametro |, parametro, . . .| ) | IS
|declaraciones locales|
BEGIN
Sentencias ejecutables
|EXCEPTION
manejadores de excepciones|
END |nombreprocedimiento|;
nombreprocedimiento ( nombreparametro , nombreparametro, . . . ] ) ]
6. 78
Notacin posicional y por nombre
Dadas las siguientes declaraciones:
DECLARE
acct INTEGER;
amt REAL;
PROCEDURE credit (acctno INTEGER, amount REAL) IS . . .
. . .
Se puede llamar al procedimiento credit de cuatro maneras
logicamente equivalentes:
BEGIN
credit(acct, amt); -- notacion posicional
credit(amount ~ amt, acctno ~ acct); -- notacion por nombre
credit(acctno ~ acct, amount ~ amt); -- notacion por nombre
credit(acct, amount ~ amt); -- notacion mezclada
. . .
END;

Paso de informacin entre procedimientos usando parmetros
Sintaxis del uso de parmetros:
PROCEDURE nombreprocedimiento (nombreparametros
modo tipo de dato |: value|)
6. 79
donde: modo puede ser IN , OUT, IN OUT.

IN: Permite el traspaso de valores a un
procedimiento. Actua como una
constante y no se le puede asignar un
valor en el procedimiento. IN es el
modo por deIecto.

OUT: Permite retornar valores hacia el que
llama al procedimiento. Actua como
una variable sin inicializar y no puede
ser asignada a otra variable o reasignada
a ella misma en el procedimiento.

IN OUT:Permite el traspaso de valores iniciales a
un procedimiento y retorna valores
actualizados al llamador. Actua como
una variable inicializada.
6. 80
PROCEDURE raisesalary (empid IN INTEGER, increase IN REAL) IS
currentsalary REAL;
salarymissing EXCEPTION;
BEGIN
SELECT sal INTO currentsalary FROM emp
WHERE empno empid;
IF currentsalary IS NULL THEN
RAISE salarymissing;
ELSE
UPDATE emp SET sal sal increase
WHERE empno empid;
END IF;
EXCEPTION
WHEN NODATAFOUND THEN
INSERT INTO empaudit VALUES (empid, No such number`);
WHEN salarymissing THEN
INSERT INTO empaudit VALUES (empid, salary is null`);
END raisesalary;
Ejemplo: Llamada a un procedimiento con parametros IN



Cuerpo del procedimiento con parametros IN

raisesalary (empnum, amount);
6. 81
Ejemplo: Llamado a un procedimiento con un parametro IN
y un parametro OUT


Cuerpo del procedimiento con los parametros IN y OUT
calcbonus(employeenum, bonusamt);
PROCEDURE calc_bonus (emp_id IN INTEGER, bonus OUT REAL) IS
hiredate DATE;
comission NUMBER (7,2);
BEGIN
SELECT hiredate, comm into hiredate, commision FROM emp
WHERE empno empid;
bonus : commission;
IF MONTHSBETWEEN (SYSDATE, hiredate) ~ 60 THEN
bonus : comission 500;
END IF;
END calcbonus;
6. 82

Ejemplo: Llamada a un procedimiento con un parametro IN
y uno IN OUT

Cuerpo del procedimiento con los parametros IN e IN OUT

debitaccount (accountnum, purchase);
PROCEDURE debitaccount (acctid IN INTEGER,
amount IN OUT REAL) IS
minimumpurchase CONSTANT REAL : 10.5;
servicecharge CONSTANT REAL : 0.50;
.
BEGIN
IF amount minimumpurchase THEN
amount : amount servicecharge;
END IF:
. . .
END debitaccount;
6. 83
Valores por defecto de los parmetros

Para el siguiente procedimiento:

PROCEDURE createdept
(newdname CHAR DEFAULT TEMP`,
newloc CHAR DEFAULT TEMP`) IS
BEGIN
INSERT INTO dept
VALUES (deptnoseq.NEXTVAL, newdname, newloc);
END createdept;

Considerar los siguientes llamados a createdept.

BEGIN
. . .
createdept;
createdept(MARKETING`);
createdept(MARKETING`, NEW YORK`);
. . .
END;
6. 84
Sobrecarga (OVERLOADING)
PL/SQL permite la sobrecarga de los nombres de los subprogramas.

Supongamos que se quiere inicializar las primeras n Iilas en
dos tablas PL/SQL que Iueron declaradas como sigue:
DECLARE
TYPE DateTabTyp IS TABLE OF DATE
INDEX BY BINARYINTEGER;
TYPE RealTabTyp IS TABLE OF REAL
INDEX BY BINARYINTEGER;
hiredatetab DateTabTyp;
saltab RealTabTyp;
. . .

Se podria escribir el siguiente procedimiento para inicializar
la tabla PL/SQL llamada hiredatetab.

PROCEDURE initialize (tab OUT DateTabTyp, n INTEGER) IS
BEGIN
FOR i IN 1..n LOOP
tab(i) : SYSDATE;
END LOOP;
END initialize;
6. 85
Se puede escribir el siguiente procedimiento para inicializar
la tabla PL/SQL llamada saltab.

PROCEDURE initialize (tab OUT RealTabTyp, n INTEGER) IS
BEGIN
FOR i IN 1..n LOOP
tab(i) : 0.0;
END LOOP;
END initialize;

Ejemplo:
DECLARE
TYPE DateTabTyp IS TABLE OF DATE
INDEX BY BINARYINTEGER;
TYPE RealTabTyp IS TABLE OF REAL
INDEX BY BINARYINTEGER;
hiredatetab DateTabTyp;
commtab RealTabTyp;
indx BINARYINTEGER;
. . .
BEGIN
indx : 50;
initialize(hiredatetab, indx); -- llama a la primera version
initialize(commtab, indx); -- llama a la segunda version
END;
6. 86
6.13.3 Funciones
Una Iuncion PL/SQL es un bloque con nombre, que se puede
llamar para que ejecute una accion especiIica y retorne un
valor.

Esqueleto de una funcin
FUNCTION ... IS








BEGIN







EXCEPTION]







END;
6. 87
Sintaxis Cuerpo de la funcin:

donde: parametro representa lo siguiente:
nombreparametro modo tipo de dato |: value|

Sintaxis Llamado a una funcin como parte de una expresin:

Debe considerarse:
Las Iunciones son especiIicas de ORACLE7 y ORACLE 8.
En la version 1.0 de PL/SQL, una Iuncion solo puede tomar
parametros IN.
Una Iuncion debe ser llamada como parte de una expresion.
Los llamados a Iunciones deIinidas por el usuario, pueden
aparecer en sentencias procedurales, pero no en sentencias SQL.
FUNCTION nombreIuncion |(parametro |, parametro, ...|) |
RETURN datatype IS
|declaraciones locales|
BEGIN
Sentencias ejecutables
|EXCEPTION
manejadores de excepciones|
END |nombrefuncion|;
. . . nombrefuncion (nombreparametro , nombreparametro, ...] ) ] ...
6. 88
Ejemplo: Llamado a una Iuncion como parte de una expresion

o

Ejemplo: Cuerpo de funcin

IF salok (newsal, level) THEN
. . .
END IF;
promotable : salok (newsal, level) AND (rating ~ 3);
FUNCTION sal_ok (salary IN REAL, level IN CHAR)
RETURN BOOLEAN IS
minsal REAL;
maxsal REAL;
BEGIN
SELECT losal, hisal INTO minsal, maxsal FROM salgrade
WHERE grade level;
RETURN (salary ~ minsal) AND (salary maxsal);
END sal_ok;
6. 89
6.13.4 Subprogramas recursivos
Ejemplo: Calcular el Iactorial de un numero.
FUNCTION fac (n POSITIVE) RETURN INTEGER IS--retorna n!
BEGIN
IF n 1 THEN -- termino de condicion
RETURN 1;
ELSE
RETURN n * Iac(n 1); --llamado recursivo
END IF;
END Iac;

Ejemplo:
FUNCTION odd (n NATURAL) RETURN BOOLEAN;
--declaracion esta mas adelante

FUNCTION even (n NATURAL) RETURN BOOLEAN IS
BEGIN
IF n 0 THEN
RETURN TRUE;
ELSE
RETURN odd(n 1); --llamado mutuamente recursivo
END IF;
END even;
6. 90
FUNCTION odd (n NATURAL) RETURN BOOLEAN IS
BEGIN
IF n 0 THEN
RETURN FALSE;
ELSE
RETURN even(n 1); -- llamado mutuamente recursivo
END IF;
END odd;

6.14 Subprogramas almacenados
6.14.1 Conceptos



Servidor
BD
Relational
DBMS
Cliente
Lgica de
Aplicacin
InterIaz
Usuario
SQL
Data
Cliente/Servidor estandar (SQL)
6. 91



Servidor
BD
Cliente
Presentacion
InterIaz
Usuario
Calls
Data
RDBMS

Lgica de
Aplicacin
Cliente/Servidor Transaccional (RPC)
BD
Servidor
D
B
M
S
Servicio
Servicio
Servicio
Cliente
L
O
G
I
C
A
Form
Form
Form
SQL RPC
Servicios disponibles a Clientes
6. 92
El servidor ORACLE es un importante cliente PL/SQL. Si se
tiene la extension procedural de bases de datos (Procedural
Database Extension), los subprogramas pueden ser
compilados en Iorma separada y almacenados
permanentemente en una base de datos ORACLE, listos para
ser ejecutados.

6.14.2 Ventajas de los subprogramas almacenados
Los subprogramas almacenados oIrecen:
Alta productividad
Mejor desempeo
Ahorro de memoria
Integridad de la aplicacion
Alta seguridad

6.14.3 Llamado a subprogramas almacenados
Se puede llamar a los subprogramas almacenados desde un
trigger de base de datos, desde otro subprograma almacenado,
desde una aplicacion del precompilador ORACLE, desde una
aplicacion OCI o desde una herramienta ORACLE, como
SQL*Plus.
6. 93
6.14.4 Funciones

Sintaxis:


Comando CREATE FUNCTION ::
CREATE
OR REPLACE
FUNCTION
schema.
function
RETURN datatype
IS
AS
cuerpo_subprograma_PL/SQL
(
argument datatype
,
IN
)
OUT
IN OUT
6. 94
Ejemplo:
CREATE FUNCTION getbal(accno IN NUMBER)
RETURN NUMBER
IS
accbal NUMBER(11,2);
BEGIN
SELECT balance
INTO accbal
FROM accounts
WHERE accountid accno;
RETURN(accbal);
END;

6.14.5 Procedimientos
Sintaxis:











Comando CREATE PROCEDURE ::
CREATE
OR REPLACE
PROCEDURE
schema.
procedure
( argument datatype
,
IN
)
OUT
IN OUT
IS
AS
cuerpo_subprograma_PL/SQL
6. 95
Ejemplo:
CREATE PROCEDURE sam.credit (accno IN NUMBER,
amount IN NUMBER) AS
BEGIN
UPDATE accounts
SET balance balance amount
WHERE accountid accno;
END;


6.14.6 Subprogramas locales versus Subprogramas
almacenados

Si se desarrolla un subprograma util, entonces se tendra una
alta posibilidad de que este sea llamado por mas de un
bloque. De acuerdo a esto, el subprograma deberia ser
almacenado en la base de datos.

Los unicos procedimientos y Iunciones que podrian
declararse locales a un bloque, deberian tender a ser cortos, y
solo ser llamados por una seccion especiIica del programa (el
bloque que los contiene).
6. 96
6.14.7 Subprogramas almacenados y el diccionario de
datos


Subprograma: Codigo Iuente
Codigo-p (Iorma compilada)


La inIormacion acerca de los subprogramas es accesible a
traves de varias vistas del diccionario de datos:


user_objects
user_source
user_errors

Sea el siguiente procedimiento simple:

CREATE OR REPLACE PROCEDURE Simple AS
vCounter NUMBER;
BEGIN
vCounter : 7;
END Simple;
6. 97
Vistas userobjecs, usersource y usererrors (sin errores)

Si se cambia el codigo anterior, tal que exista un error (notar
que Ialta el punto y coma):

CREATE OR REPLACE PROCEDURE Simple AS
vCounter NUMBER;
BEGIN
vCounter : 7
END Simple;
6. 98
Vistas userobjects, usersource y usererrors (con errores)


En SQL*Plus, el comando SHOW ERRORS consultara
user_errors y Iormateara la salida para que sea legible.

Se puede usar SHOW ERRORS despues de recibir el mensaje
'Warning: Procedure created with compilation errors.

: 7
6. 99
6.14.8 Dependencias en los subprogramas

Cuando un procedimiento o una Iuncion es compilada, todos
los objetos ORACLE a los que hace reIerencia son
registrados en el diccionario de datos. El procedimiento es
dependiente de estos objetos.

Dependencias de RecordFullClases
La funcin AlmostFull
depende directamente
de classes.
El procedimiento
RecordFullClasses
depende directamente de
temp_table y AlmostFull e
indirectamente de classes.
classes
temptable
AlmostFull
RecordFullClasses
6. 100
Invalidacion como resultado de una operacion DDL
6. 101
6.14.9 Paquetes

A. Formato General ( Pseudocodigo):

PACKAGE nombrepaquete~ IS
/*
** ESPECIFICACION DEL PAQUETE
** Declaraciones publicas de tipos de datos, variables,
constantes, excepciones y cursores.
** EspeciIicaciones publicas de procedimientos y Iunciones
(declaraciones 'Iorward)
*/
END |nombrepaquete|;


PACKAGE BODY nombrepackage~ IS
/*
** CUERPO DEL PAQUETE
** Declaraciones privadas de tipos de datos, variables,
constantes excepciones y cursores.
** Cuerpos de procedimientos y Iunciones publicos y privados.
*/
|BEGIN
-- sentencias de inicializacion|
END |nombrepaquete|;

donde:
nombre_paquete, es un nombre unico dentro del
alcance de un esquema de base de datos
6. 102
B. Comando CREATE PACKAGE

Sintaxis:

Un paquete es una coleccion encapsulada de:
Procedimientos
Funciones
Variables
Constantes
Cursores
Excepciones

Comando CREATE PACKAGE::
CREATE
OR REPLACE
PACKAGE
schema.
package
IS
AS
pl/sql_package_spec
6. 103
Ejemplo:
CREATE PACKAGE empmgmt AS
FUNCTION hire (ename VARCHAR2, job VARCHAR2,
mgr NUMBER, sal NUMBER, comm NUMBER,
deptno NUMBER)
RETURN NUMBER;

FUNCTION createdept (dname VARCHAR2, loc VARCHAR2)
RETURN NUMBER;

PROCEDURE removeemp (empno NUMBER);

PROCEDURE removedept (deptno NUMBER);

PROCEDURE increasesal(empno NUMBER, salincr NUMBER)

PROCEDURE increasecomm (empno NUMBER,
commincr NUMBER);
nocomm EXCEPTION;
nosal EXCEPTION;
END empmgmt
6. 104
C. Comando CREATE PACKAGE BODY

Sintaxis:

Comando CREATE PACKAGE BODY ::
CREATE
OR REPLACE
PACKAGE BODY
schema.
package
IS
AS
pl/sqlpackagebody
6. 105
Ejemplo:
CREATE PACKAGE BODY empmgmt AS
totemps NUMBER;
totdepts NUMBER;

FUNCTION hire (ename VARCHAR2, job VARCHAR2,
mgr NUMBER, sal NUMBER, deptno NUMBER)
RETURN NUMBER IS
newempno NUMBER(4);
BEGIN
SELECT empseq.NEXTVAL
INTO newempno
FROM DUAL;
INSERT INTO emp
VALUES (newempno, ename, job, mgr,
sal, comm, deptno)
totemps : totemps 1;
RETURN (newempno);
END;

6. 106
FUNCTION create_dept (dname VARCHAR2, loc VARCHAR2)
RETURN NUMBER IS
newdeptno NUMBER(4);
BEGIN
SELECT deptseq.NEXTVAL
INTO newdeptno
FROM dual;
INSERT INTO dept
VALUES (newdeptno, dname, loc);
totdepts : totdepts 1;
RETURN (newdeptno);
END;


PROCEDURE remove_emp(empno NUMBER) IS
BEGIN
DELETE FROM emp
WHERE emp.empno removeemp.empno;
totemps : totemps 1;
END;

6. 107
PROCEDURE remove_dept(deptno NUMBER) IS
BEGIN
DELETE FROM dept
WHERE dept.deptno removedept.deptno;
totdepts : totdepts 1;
SELECT COUNT(*)
INTO totemps
FROM emp;
/* En caso de que ORACLE elimine
empleados desde la tabla EMP, para asegurar
las restricciones de integridad reIerencial, se
resetea el valor de la variable TOTEMPS al
numero total de empleados en la tabla EMP.*/
END;

6. 108
PROCEDURE increase_sal (empno NUMBER, salincr NUMBER) IS
currsal NUMBER(7,2);
BEGIN
SELECT sal
INTO currsal
FROM emp
WHERE emp.empno increasesal.empno;
IF currsal IS NULL
THEN RAISE nosal;
ELSE UPDATE emp
SET sal sal salincr
WHERE emp.empno increasesal.empno;
END IF;
END;

PROCEDURE increase_comm (empno NUMBER,
commincr NUMBER) IS
currcomm NUMBER(7,2);
BEGIN
SELECT comm
INTO currcomm
FROM emp
WHERE emp.empno increasecomm.empno;
IF currcomm IS NULL
THEN RAISE nocomm;
ELSE UPDATE emp
SET comm comm commincr
WHERE emp.empno increasecomm.empno;
END;
.
END empmgmt;
6. 109
D. Referencias al contenido del paquete
Los contenidos publicos del paquete pueden ser
reIerenciados, usando notacion de punto.
Ejemplo:
nombrepaquete.nombretipodato
o
nombrepaquete.nombrevariable
o
nombrepaquete.nombreprocedimiento(. . . );
o
nombrepaquete.nombreIuncion(. . .);

6.15 Triggers (Disparadores)
A. Conceptos
Es un procedimiento que el sistema ejecuta automaticamente,
como un eIecto secundario de una modiIicacion de la base de
datos.

Para disear un mecanismo de disparador se deben:
EspeciIicar las condiciones bajo las cuales se va a
ejecutar el disparador.
EspeciIicar las acciones que se van a tomar cuando se
ejecute el disparador.
6. 110
El SQL estandar no incluye disparadores; existen diversas
versiones de SQL, con sus propias caracteristicas de
disparadores no estandar.

Los triggers son usados a menudo, para iniciar procesos de
negocio secundarios. Por ejemplo, pueden ser usados para
comenzar las siguientes operaciones:

VeriIicar la integridad de los datos en inserciones o
actualizaciones.
Implementar eliminaciones en cascada.
Transparentemente eIectuar eventos de bitacora (log)
Asegurar el cumplimiento de complejas reglas de
negocios.
Iniciar procesos de negocios.
Derivar valores de columnas automaticamente.
Forzar complejas reglas de seguridad.
Mantencion de datos replicados.


6. 111
Ejemplo:
Trigger REORDER

Sentencia de triggering
AFTER UPDATE OF partsonhand ON inventory
Restriccin del trigger
WHEN (new.partsonhand new.reorderpoint)
Accin del trigger
FOR EACH ROW
DECLARE /* una variable dummy para contar*/
NUMBER x;
BEGIN
SELECT COUNT(*) INTO x /*consulta para encontrar si las partes han */
FROM pendingorders /* sido reordenadas si es si, x1, si es no x0 */
WHERE partno:new.partno;
IF x0
THEN /* partes que no han sido pedidas de nuevo,*/
INSERT INTO pendingorders /* se piden de nuevo */
VALUES (:new.partno, :new.reorderquantity,sysdate)
ENDIF; /* la parte ya ha sido pedida*/
END;
6. 112
SINTAXIS:

CREATE |OR REPLACE| TRIGGER nombretrigger~
BEFORE , AFTER}
DELETE , INSERT , UPDATE |OF nombrecolumna1
|, nombrecolumn2| . . . | }
|OR DELETE , INSERT , UPDATE |OF columna
|, columna| . . . |}| . . .
ON nombretabla~
| | REFERENCING OLD |AS| old |NEW |AS| new|
, NEW |AS| new |OLD |AS| old| } |
|FOR EACH ROW
|WHEN (condicion) | |
|DECLARE|
. . .
BEGIN
. . .
|EXCEPTION
. . . |
END;

6. 113
donde:
nombre_trigger: es el nombre del trigger; debe ser
unico dentro del esquema de la base de datos.
nombre_tabla: es el nombre de la tabla a la cual se
asocia el trigger.

B. Opciones de los triggers de base de datos
Cada trigger tiene tres opciones:
La primera opcion, que considera 2 casos, especiIica
cuando es iniciado el trigger: BEFORE (antes) o AFTER
(despues) de una operacion especiIica sobre la tabla.
La segunda opcion, que considera 3 casos, especiIica la
operacion que activa el trigger: INSERT, UPDATE o
DELETE. Estas operaciones pueden ser especiIicadas
individualmente, o en cualquier combinacion
incluyendolas todas a la vez. Por ejemplo:
INSERT
INSERT OR DELETE
DELETE OR UPDATE
INSERT OR UPDATE
DELETE OR UPDATE OR INSERT
6. 114
La tercera opcion, que considera 2 casos, especiIica si el
trigger sera ejecutado solo una vez por cada operacion
sobre la tabla (deIault), o una vez para cada Iila aIectada
por la operacion que activa el trigger (FOR EACH ROW).
En este ultimo caso, se tiene un trigger de Iila.

Opciones de los triggers de base de datos
Before o After Insert, Update o Delete For Each Row
BEFORE INSERT
BEFORE UPDATE
BEFORE DELETE
BEFORE INSERT FOR EACH ROW
BEFORE UPDATE FOR EACH ROW
BEFORE DELETE FOR EACH ROW
AFTER INSERT
AFTER UPDATE
AFTER DELETE
AFTER INSERT FOR EACH ROW
AFTER UPDATE FOR EACH ROW
AFTER DELETE FOR EACH ROW

6. 115
C. Orden de disparo de los triggers
El algoritmo para ejecutar una sentencia DML es el siguiente:
1. Ejecutar el trigger beIore a nivel de sentencia, si esta
presente.
2. Por cada Iila aIectada por la sentencia:
a) Ejecutar el trigger beIore a nivel de Iila, si esta
presente.
b) Ejecutar la sentencia en si.
c) Ejecutar el trigger aIter a nivel de Iila, si esta
presente.
3. Ejecutar el trigger aIter a nivel de sentencia, si esta
presente.

Opcin WHEN
Opcionalmente, una condicion booleana puede ser
especiIicada para un trigger de Iila.
Si se especiIica, la condicion WHEN es evaluada para cada
Iila aIectada por la operacion de la tabla.
Si la condicion del WHEN se evalua a TRUE para una Iila
aIectada por la operacion sobre la tabla, el trigger es
disparado para esa Iila.
6. 116
Sin embargo, si la condicion WHEN se evalua FALSE o
null para una Iila aIectada por la operacion sobre la tabla,
el trigger no se dispara para esa Iila.

Opciones condicionales
Debido a que un trigger de base de datos puede ser creado
para multiples operaciones de una tabla (por ejemplo,
'INSERT OR DELETE OR UPDATE OF...), las opciones
condicionales o predicados pueden ser usados en el cuerpo
del trigger para distinguir entre que operacion ha causado el
disparo del trigger.

Estos predicados condicionales son INSERTING,
DELETING y UPDATING.

Ellos son usados para ejecutar secciones especiIicas del
cuerpo de un trigger de base de datos, segun la operacion que
disparo el trigger de base de datos.

Por ejemplo:
INSERT OR UPDATE ON item . . .
6. 117
Dentro del cuerpo del trigger, podrian ser especiIicadas las
siguientes condiciones:
IF INSERTING THEN
. . .
END IF;
IF UPDATING THEN
. . .
END IF;

Ejemplo:

CREATE TRIGGER . . .
. . .UPDATE OF itemcost, itemname ON item. . .
BEGIN
IF UPDATING (ITEMCOST`) THEN
. . .
END IF;
END;


6. 118
D. Pseudoregistros :old y :new
Un trigger a nivel de Iila se dispara una vez por cada Iila
procesada. Dentro del trigger, se puede accesar la Iila que
esta siendo actualmente procesada, a traves de los
pseudoregistros: old y :new

El tipo de ambos es:
triggeringtableROWTYPE;
donde triggeringtable es la tabla para la cual se deIine el trigger.

:old y :new
Sentencias
del Trigger
:old :new
INSERT IndeIinido. Todos los campos
son nulos.
Valores que seran insertados
cuando la sentencia esta
completa.
UPDATE Valores originales para la Iila
antes de la actualizacion.
Nuevos valores que seran
actualizado cuando la
sentencia esta completa.
DELETE Valores originales antes de
que la Iila sea eliminada.
IndeIinido. Todos los
campos son nulos.
6. 119
E. Los triggers y el diccionario de datos
Cuando se crea un trigger, su codigo Iuente es almacenado en
la vista del diccionario de datos user_triggers.

Ejemplo:
SQL~ SELECT triggertype, tablename, triggeringevent
2 FROM usertriggers
3 WHERE triggername UPDATEMAJORSTATS`;

TRIGGERTYPE TABLENAME TRIGERRINGEVENT
AFTER
STATEMENT
STUDENTS INSERT OR UPDATE
OR DELETE

F. Borrado y deshabilitacin de los triggers
SQL~ DROP TRIGGER nombretrigger

SQL~ ALTER TRIGGER UpdateMajorStats DISABLE
Trigger altered

SQL~ ALTER TRIGGER UpdateMajorStats ENABLE;
Trigger altered
6. 120
SQL~ ALTER TABLE students
2 ENABLE ALL TRIGGERS;
Table altered

SQL~ ALTER TABLE students
2 DISABLE ALL TRIGGERS;
Table altered

La columna status de user_triggers contiene ENABLED` o
DISABLED`, que indican el estado actual del trigger.


G. Ejemplo
Este ejemplo crea un trigger de Iila BEFORE, llamado
SALARYCHECK en el esquema SCOTT. Cuando se
agregue un nuevo empleado a la tabla employee o a un
empleado existente se le cambie el salario o el trabajo, este
trigger garantiza que el salario del empleado cae dentro del
rango de salario establecido para los empleados de ese
trabajo.
6. 121
CREATE TRIGGER scott.salarycheck
BEFORE
INSERT OR UPDATE OF sal, job
ON scott.emp
FOR EACH ROW
WHEN (new.job ~ PRESIDENT`)
DECLARE
minsal NUMBER;
maxsal NUMBER;
BEGIN
/*Obtiene el salario minimo y el maximo para el */
/*trabajo del empleado desde la tabla SALGUIDE */
SELECT minsal, maxsal
INTO minsal, maxsal
FROM salguide
WHERE job :new.job;
/*Si el salario del empleado es menor que el minimo */
/*o arriba del maximo para ese trabajo, se genera un error */
IF (:new.sal minsal OR :new.sal ~ maxsal)
THEN raiseapplicationerror (-20601, Salario`
,, :new.sal ,, Iuera del rango para el trabajo`
,,:new.job ,, para el empleado` ,, :new.ename);
END IF;
END;
6. 122
6.16 Objetos en el esquema
Tables
Views
Sequences
Procedures
Functions
Packages
Synonyms
Indexes
Cluster, HashClusters
Database Links
Snapshots
Constraints
Database Triggers

B.D.

SABD
6. 123
6.17 Ambiente SQL`Plus para ejecutar bloques PL/SQL

Despues de entrar al ambiente SQL*Plus, se puede usar
PL/SQL de varias maneras:

Ingresar y almacenar bloques PL/SQL.
Ingresar y correr bloques PL/SQL.
Crear un script conteniendo bloques PL/SQL.
Cargar y correr un script conteniendo bloques PL/SQL.
Llamar a un subprograma almacenado.

A. Entrando un bloque annimo

Cada bloque PL/SQL comienza con la palabra reservada
DECLARE o, si el bloque no tiene parte declarativa, con la
palabra reservada BEGIN. Al entrar la palabra reservada,
SQL*Plus eIectua lo siguiente:
Limpia el buIIer SQL.
Entra al modo INPUT.
Ignora los punto y coma (terminador de una sentencia SQL).
6. 124
Se entra el resto del bloque PL/SQL linea por linea. Se
termina con un punto Iinal (.) en una linea, que permite
almacenar el bloque, en el buIIer SQL.

Se puede salvar el bloque PL/SQL en un archivo script como sigue:
SQL~ SAVE nombrearchivo~
SQL~ SAVE nombrearchivo~ REPLACE

B. Ejecucin de un bloque annimo

Una vez que esta almacenado en el buIIer SQL, se puede
correr el bloque PL/SQL como sigue:

SQL~ RUN
O
SQL~ /


6. 125
C. Creacin de un script
Ejemplo:
CLEAR BREAKS;
CLEAR COLUMNS;
COLUMN ENAME HEADING NAME;
TTITLE CLERICAL STAFF`;
DECLARE
avgsal NUMBER(7,2);
BEGIN
SELECT AVG(sal) INTO avgsal FROM emp;
IF avgsal 1500 THEN
UPDATE emp SET sal sal * 1.05 WHERE job CLERK`;
END IF;
END;
/
SELECT ENAME, SAL FROM EMP WHERE JOB CLERK`;

D. Cargando y corriendo un script
SQL~ GET nombrearchivo~
SQL> START <nombrearchivo>

E. Llamando a subprogramas almacenados
SQL~ EXECUTE createdept (ADVERTISING`, NEW YORK`);

Este llamado es equivalente al siguiente bloque anonimo PL/SQL:
SQL> BEGIN createdept (ADVERTISING`, NEW YORK`); END;
6. 126
6.18 PL/SQL Dinmico

6.18.1 Introduccin

En general, un lenguaje de programacion puede enlazar
variables de 2 maneras: tarde o temprano.
Ligar una variable es el proceso de identiIicar la
localizacion del almacenamiento asociada con un
identiIicador en el programa.
En PL/SQL el ligamiento involucra tambien el chequeo de
la base de datos para los permisos de acceso al objeto
reIerenciado.

Un lenguaje que usa solo ligamiento temprano hace el
ligamiento durante la fase de compilacin mientras, que
un lenguaje que usa el ligamiento tarde pospone el
ligamiento hasta el tiempo de ejecucin.

Ligamiento temprano signiIica que la fase de
compilacin tomar mucho ms tiempo (ya que el
trabajo del ligamiento tiene que ser hecho), pero la
ejecucin ser ms rpida, puesto que el ligamiento ya ha
sido completado.
6. 127
El ligamiento tarde acorta el tiempo de compilacin
pero alarga el tiempo de la ejecucin.

Una de las decisiones de diseo para PL/SQL fue el uso
del ~Early Binding (Ligamiento temprano).
Esta decision Iue tomada de manera que la ejecucion de un
bloque Iuera tan rapida como sea posible, porque todos
los objetos de la base de datos ya han sido veriIicados por
el compilador.
Esto tiene sentido, puesto que los bloques PL/SQL pueden
ser almacenados dentro de la base de datos via
procedimientos, Iunciones, paquetes y triggers.
Estos objetos se guardan en Iorma compilada, de manera
que cuando sean necesitados ellos puedan ser cargados
desde la base de datos a la memoria y luego ejecutados.

La principal consecuencia de esta decisin es que
PL/SQL puede contener solamente sentencias DML y
de control de transacciones, no sentencias DDL.
6. 128
Para ilustrar esto, considere el hipotetico bloque PL/SQL:

BEGIN
CREATE TABLE temptable (
numvalue NUMBER,
charvalue CHAR (10));

INSERT INTO temptable (numvalue, charvalue)
VALUES (10, Hello`);
END;

Para compilar esto, el identiIicador temptable necesita ser
ligado.
Este proceso chequeara para ver si esta tabla existe.
Sin embargo, la tabla no existira hasta que el bloque este
en ejecucion.
Pero si el bloque no puede ser aun compilado, no hay
Iorma de que pueda ser ejecutado.
Las sentencias DML y las de control de transacciones, son
las unicas sentencias SQL que no tienen el potencial para
modiIicar el objeto o permisos de acceso sobre los objetos,
por lo tanto son sentencias SQL legales en PL/SQL.
6. 129
Con el PL/SQL 2.1 y superior, esta restriccin es
levantada, a travs del paquete DBMS_SQL.

Este paquete permite crear una sentencia SQL
dinamicamente en tiempo de ejecucion, y luego parsearla y
ejecutarla.
Puesto que la sentencia realmente no se crea hasta el
tiempo de ejecucion, el compilador de PL/SQL no tiene
que ligar los identiIicadores en la sentencia, lo cual permite
al bloque compilar.
Por ejemplo, podriamos usar el paquete DBMSSQL para
ejecutar la sentencia CREATE TABLE en el bloque
anterior.
Sin embargo, la sentencia INSERT Iallaria al ser
compilada puesto que la tabla no existira hasta que el
bloque sea ejecutado.
La solucion a este problema es usar DBMSSQL para
ejecutar la sentencia INSERT tambien.

6. 130
El paquete DBMSSQL implementa el SQL y el PL/SQL
dinamico, llamado desde otros bloques PL/SQL.

Esencialmente, DBMSSQL externaliza el proceso normal
de ejecutar SQL y PL/SQL, y lo pone bajo nuestro control.

Debido a que el proceso completo esta bajo el control del
programa, se puede utilizar DBMSSQL, tanto para
sentencias DDL como DML.

La version 8.1 de PL/SQL para el servidor ORACLE 8i
proporciona capacidades de SQL dinamico, directamente
en el lenguaje PL/SQL, utilizando una nueva sintaxis y
extensiones de la sintaxis existente.
6. 131

CREATE PROCEDURE insert_into_table (
tablename VARCHAR2, deptnumber NUMBER,
deptname VARCHAR2, location VARCHAR2) IS
curhdl INTEGER;
stmtstr VARCHAR2(200);
rowsprocessed BINARYINTEGER;
BEGIN
stmtstr : 'INSERT INTO ' ,, tablename ,, '
VALUES (:deptno, :dname, :loc)';
-- open cursor
curhdl : dbmssql.opencursor;
-- parse cursor
dbmssql.parse(curhdl, stmtstr, dbmssql.native);
-- supply binds
dbmssql.bindvariable (curhdl, ':deptno', deptnumber);
dbmssql.bindvariable (curhdl, ':dname', deptname);
dbmssql.bindvariable (curhdl, ':loc', location);
-- execute cursor
rowsprocessed : dbmssql.execute(curhdl);
-- close cursor
dbmssql.closecursor(curhdl);
END;
Con la versin antigua de PL/SQL
6. 132




CREATE PROCEDURE insert_into_table (

tablename VARCHAR2,
deptnumber NUMBER,
deptname VARCHAR2,
location VARCHAR2) IS

stmtstr VARCHAR2(200);

BEGIN

stmtstr : `INSERT INTO ` ,,
tablename ,, ` values
(:deptno, :dname, :loc)`;

EXECUTE IMMEDIATE stmtstr USING
deptnumber, deptname, location;
END;
Ahora con la
versin nueva de
PL/SQL
6. 133
DECLARE
sqlstmt VARCHAR2(200);
plsqlblock VARCHAR2(500);
empid NUMBER(4) : 7566;
salary NUMBER(7,2);
deptid NUMBER(2) : 50;
deptname VARCHAR2(14) : `PERSONNEL`;
location VARCHAR2(13) : `DALLAS`;
emprec empROWTYPE;

BEGIN
EXECUTE IMMEDIATE `CREATE TABLE
bonus (id NUMBER, amt NUMBER)`;

sqlstmt : `INSERT INTO dept VALUES (:1, :2, :3)`;
EXECUTE IMMEDIATE sqlstmt USING
deptid, deptname, location;

sqlstmt : `SELECT * FROM emp WHERE empno :id`;
EXECUTE IMMEDIATE sqlstmt INTO
emprec USING empid;
END;
6. 134
DECLARE

TYPE EmpCurTyp IS REF CURSOR;
empcv EmpCurTyp;
emprec empROWTYPE;
sqlstmt VARCHAR2(200);
myjob VARCHAR2(15) : `CLERK`;

BEGIN

sqlstmt : `SELECT * FROM emp WHERE job :j`;

OPEN empcv FOR sqlstmt USING myjob;
LOOP
FETCH empcv INTO emprec;
EXIT WHEN empcvNOTFOUND;
-- process record
END LOOP;
CLOSE empcv;

END;
6. 135
CREATE OR REPLACE PROCEDURE query_invoice (
month VARCHAR2, year VARCHAR2) IS
TYPE curtyp IS REF CURSOR;
c curtyp;
querystr VARCHAR2(200);
invnum NUMBER : 100;
invcust VARCHAR2(20);
invamt NUMBER;
BEGIN
querystr : 'SELECT num, cust, amt FROM
inv' ,, month ,,``,, year ,, ' WHERE invnum :id';
OPEN c FOR querystr USING invnum;
LOOP
FETCH c INTO invnum, invcust, invamt;
EXIT WHEN cNOTFOUND;
--process row here

END LOOP;
CLOSE c;
END;

S-ar putea să vă placă și