PL_SQL

34
DESARROLLO DE APLICACIONES CON PL/SQL JUAN MANUEL MADRID MOLINA

Transcript of PL_SQL

7/16/2019 PL_SQL

http://slidepdf.com/reader/full/plsql-5633867273692 1/34

DESARROLLO DE APLICACIONES

CON PL/SQL

JUAN MANUEL MADRID MOLINA

7/16/2019 PL_SQL

http://slidepdf.com/reader/full/plsql-5633867273692 2/34

TABLA DE CONTENIDO

1. INTRODUCCION 11.1. ¿Qué es PL/SQL? 11.2. Estructura de un bloque PL/SQL. 1

2. DECLARACION DE VARIABLES 32.1. Objetivos 32.2. Declaración de variables y constantes. 32.3. Alcance de las variables y las constantes. 5

EJERCICIOS CAPITULO 1 63. CODIFICACION DE INSTRUCCIONES SQL EN PL/SQL 8

3.1. Objetivos. 83.2. Instrucciones SQL en PL/SQL. 83.3. Uso de funciones de SQL. 9

4. CODIFICACION DE INSTRUCCIONES DE CONTROL CONDICIONALE ITERATIVO 11

4.1. Objetivos. 114.2. Comparaciones lógicas. 114.3. Uso del IF-THEN-ELSE. 11

LABORATORIO CAPITULO 4 - PARTE 1 134.4. Uso de ciclos repetitivos. 15

4.4.1. Ciclos simples. 154.4.2. Ciclos FOR numéricos. 154.4.3. Ciclos WHILE. 16

4.5. Uso del GOTO y las etiquetas. 17LABORATORIO CAPITULO 4 - PARTE 2 195. DECLARACION Y USO DE CURSORES 20

5.1. Objetivos. 205.2. ¿Qué es un cursor? 205.3. Uso de cursores explícitos. 205.4. Ciclos FOR de cursor. 245.5. Uso del cursor implícito. 25

LABORATORIO CAPITULO 5 266. MANEJO DE ERRORES EN PL/SQL 27

6.1. Objetivos. 27

6.2. ¿Qué son las excepciones? 276.3. Funciones para reporte de errores. 31

LABORATORIO CAPITULO 6 32

7/16/2019 PL_SQL

http://slidepdf.com/reader/full/plsql-5633867273692 3/341

1. INTRODUCCION

1.1. ¿Qué es PL/SQL?

Muchas veces, durante la programación en Oracle, el programador se ve en la necesidadde combinar instrucciones procedimentales (instrucciones que se emplearían en unlenguaje de 3ª generación, como WHILE, REPEAT, IF...THEN...ELSE, etc.). Trabajandoen SQL*Plus, esto es demasiado difícil, si no imposible.

Surgen entonces, dos maneras de combinar instrucciones procedimentales coninstrucciones 4GL:• Hacer una interfaz con un lenguaje de 3ª generación (C, Pascal...)

• Integrar un procesador de instrucciones procedimentales en Oracle.

Ambas soluciones existen. La primera es la serie de preprocesadores Pro*Oracle paralenguajes de 3ª generación (Pro*C, Pro*COBOL, etc.). La segunda es una extensión delmotor de Oracle llamada PL/SQL.

Un bloque de programa PL/SQL es enviado como un todo al motor de la base de datos. Elmotor envía las instrucciones procedimentales a una sección llamada ejecutor deinstrucciones procedimentales, y las instrucciones SQL al ejecutor normal de instruccionesSQL. Todas estas actividades se coordinan de la manera adecuada para obtener losresultados deseados.

Entre las ventajas de PL/SQL se pueden mencionar:• Mayor integración de las aplicaciones con el motor ORACLE.• Portabilidad.• Velocidad de ejecución.

1.2. Estructura de un bloque PL/SQL.Un bloque PL/SQL se compone de 3 partes:Una sección de declaración de variables y estructuras.Una sección de código ejecutable.Una sección de manejadores de excepción.

Esto se conoce como la estructura DECLARE, BEGIN, EXCEPTION, END; y el ordenque lleva se puede apreciar en la figura siguiente.

7/16/2019 PL_SQL

http://slidepdf.com/reader/full/plsql-5633867273692 4/342

DECLARE

BEGIN

EXCEPTION

END;

Debe notarse que los bloques pueden contener, a su vez, subbloques. Estos subbloques pueden aparecer en cualquier sitio que una instrucción ejecutable podría aparecer legalmente.

Cada instrucción finaliza con un ; (punto y coma).

Los comentarios se rodean con /* */ , o se preceden con -- (doble guión).

La existencia de los objetos que se declaren en el bloque DECLARE está sujeta a sualcance (ver más adelante la parte referente a este tema).

7/16/2019 PL_SQL

http://slidepdf.com/reader/full/plsql-5633867273692 5/343

2. DECLARACION DE VARIABLES

2.1. Objetivos

Al finalizar esta sección, el lector estará en capacidad de:• Identificar declaraciones legales e ilegales de PL/SQL.• Aplicar el concepto de alcance de las variables y constantes para hallar valores de

variables en un bloque PL/SQL.

2.2. Declaración de variables y constantes.Los tipos de datos soportados en PL/SQL son: NUMBER 

CHAR/VARCHAR2DATEBOOLEAN

Los tipos NUMBER, CHAR y DATE se comportan de la misma manera que en elRDBMS. El tipo BOOLEAN no tiene correspondencia en el RDBMS, y puede contener los valores TRUE, FALSE o NULL.

SINTAXIS DE LA DECLARACION:identificador [CONSTANT] tipo_de_datos [NOT NULL] [:=expresión_plsql];

Ejemplos:DECLAREnombre, apellido CHAR(20); -- ilegal

DECLAREnombre CHAR(20); -- legalapellido CHAR(20); -- legal

NOTAS:• Las reglas para los identificadores son las mismas que para los objetos SQL.• Se puede usar el NOT NULL para restringir una variable, de manera que nunca pueda

ser nula. Las variables declaradas como NOT NULL deben inicializarse.

• Sólo se permite un identificador por línea.• No se permiten arreglos.

Más ejemplos:DECLAREcuenta NUMBER;ventas NUMBER(9,2);segundos_día CONSTANT NUMBER := 60*60*24;

7/16/2019 PL_SQL

http://slidepdf.com/reader/full/plsql-5633867273692 6/344

total_corrida NUMBER(10,0) := 0;

inicial CHAR;apellido CHAR(10) NOT NULL := 'SNOOPY';nom_cia CONSTANT CHAR(12) := 'ORACLE';

aniversario DATE := '05-JUL-59';fin_proyecto DATE;sig_chequeo DATE NOT NULL := '28-DEC-89';

valido BOOLEAN NOT NULL := FALSE;disponible BOOLEAN := NULL;

USO DE %TYPE Y %ROWTYPE

Los objetos de la base de datos (tablas, columnas) y los objetos de PL/SQL (variables yconstantes) se pueden relacionar mediante el uso de %TYPE y %ROWTYPE. Estosatributos son útiles cuando se desea estar seguro que dos tipos de objetos coincidentotalmente.

Ejemplos:DECLARElibros_impresos NUMBER(6);libros_vendidos libros_impresos%TYPE;nombre_dama emp.ename%TYPE;dept_row dept%ROWTYPE;

En este caso, la variable libros_vendidos tendrá el mismo tipo de datos delibros_impresos. La variable nombre_dama tendrá el tipo de la columna ENAME de latabla EMP. La variable dept_row será un registro con la misma estructura de una fila de

la tabla DEPT. Su componentes se acceden de la siguiente manera: dept_row.deptno,dept_row.ename y dept_row.loc.

EXPRESIONES Y ASIGNACIONESLa sintaxis de una asignación es:

variable_plsql := expresión_plsql;

• Nótese que se emplea el símbolo := para asignar, y = para comparaciones.• El tipo de datos en ambos lados de la asignación debe ser igual, o convertible

implícitamente. (Las conversiones de CHAR a NUMBER o DATE son automáticas;de NUMBER o DATE a CHAR deben efectuarse explícitamente con la función

TO_CHAR).• No se admiten referencias a columnas o a tablas en ninguno de los lados de la

asignación.

Ejemplos de asignaciones: N=Number C=Char B=Boolean D=Date

 N := 5 * N2 *O.7;

B := TRUE;

7/16/2019 PL_SQL

http://slidepdf.com/reader/full/plsql-5633867273692 7/345

D := '11-JUN-87';

 N := N2 + SQRT((N2**2 - 4*N3*N4) / 2*N3);

B := (EN_STOCK) OR (PUEDE_PEDIRSE);

 N/C/B/D := 'Antonio ' || 'y' || ' Cleopatra';

B := NULL;

C := TO_CHAR(N1**2);B := N1 > 2*N2;

2.3. Alcance de las variables y las constantes.El ALCANCE se refiere a la visibilidad de los identificadores en diferentes puntos de un bloque PL/SQL.

REGLAS DE ALCANCE:1. Un identificador es visible en el bloque en que se declare y en todos sus sub-bloques, a

menos que se cumpla la regla #2.2. Si un identificador declarado en un bloque es redeclarado en un sub-bloque, el

identificador original no es visible dentro del sub-bloque (se ve el redeclarado). Esteidentificador redeclarado tiene las reglas de alcance definidas en la regla 1.

7/16/2019 PL_SQL

http://slidepdf.com/reader/full/plsql-5633867273692 8/346

EJERCICIOS CAPITULO 1

Revise cada una de las siguientes declaraciones. Diga cuáles no están correctas, y explique por qué.

DECLAREmi_var NUMBER(7,2);DECLAREx,y,z CHAR(10);DECLAREtam_max CONSTANT NUMBER := 256;DECLAREfecha_nac DATE NOT NULL;DECLAREen_stock BOOLEAN := 1;DECLARE

nombre CHAR(15);inicial CHAR;

DECLAREpeso NUMBER := 600;lugar CHAR(10) := 'Europa';

BEGIN

DECLAREpeso NUMBER := 1;otro_lugar CHAR(20);

BEGIN

peso := peso+1; Œotro_lugar := lugar || ' Occidental'; •

END;

DECLAREotro_peso NUMBER;continente CHAR(10);

BEGINcontinente := lugar; Žotro_peso := peso + 10;

END;

peso := peso -50; lugar := otro_lugar || ' y Asia'; ‘

END;

Evalúe el bloque PL/SQL anterior. Aplique las reglas de alcance para determinar losvalores donde se indica.

7/16/2019 PL_SQL

http://slidepdf.com/reader/full/plsql-5633867273692 9/347

Œ

Ž

7/16/2019 PL_SQL

http://slidepdf.com/reader/full/plsql-5633867273692 10/348

3. CODIFICACION DE INSTRUCCIONES SQL EN PL/SQL

3.1. Objetivos.

Al finalizar esta sección, el lector estará en capacidad de:• Usar instrucciones SQL en procedimientos PL/SQL.• Identificar las funciones SQL soportadas en PL/SQL.

3.2. Instrucciones SQL en PL/SQL.

• Los comandos SQL soportados en PL/SQL son los comandos DML del SQL(INSERT, UPDATE, DELETE, SELECT...INTO).

• Se pueden colocar variables PL/SQL en cualquier lugar que se pueda colocar 

legalmente una constante.• Los identificadores se chequean primero para comprobar si son columnas de la base de

datos. Si no se encuentra en la base de datos, se asume que es un identificador PL/SQL.

• Las instrucciones PL/SQL no pueden aparecer como parte de una expresión.• No se soportan comandos DDL ni DCL del SQL (ALTER, DROP, CREATE...)

Ejemplo de INSERT:DECLAREsueldo NUMBER(7,2) := 3040.55;nombre CHAR(25) := 'PEDRO';

ingreso DATE := '08-SEP-88';

BEGININSERT INTO emp (empno, ename, job, hiredate, sal, deptno)VALUES (2741,nombre,'CHOFER',ingreso,sueldo,20);END;

Ejemplo de UPDATE:DECLAREmaximo CONSTANT NUMBER := 5000;buen_cli CHAR(8) := 'VIP';

BEGINUPDATE cuentas SET limite_credito = maximoWHERE estado = 'PAZ Y SALVO' OR estado = 'buen_cli';END;Ejemplo de DELETE:DECLAREtipo_pers CHAR(8) := 'Odioso';

BEGIN

7/16/2019 PL_SQL

http://slidepdf.com/reader/full/plsql-5633867273692 11/349

DELETE FROM lista_amigosWHERE tipo_amigo = tipo_pers;END;

Uso del SELECT INTO:• El SELECT es la única instrucción DML que retorna datos. El sitio donde quedarán

estos datos se especifica por medio de la cláusula INTO.• Las instrucciones SELECT...INTO deben retornar exactamente una fila. Si no se

retorna ninguna o se retornan varias, se genera un error. Para SELECTs de múltiplesfilas se emplean los cursores (ver más adelante).

SINTAXIS DEL SELECT...INTO:SELECT col1, col2, ... INTO var1, var2, ...FROM nombre_tabla WHERE ...

Ejemplo:DECLAREnom_parte partes.nombre%TYPE;

en_stock partes.num%TYPE;

BEGINSELECT nombre, num INTO nom_parte, en_stockFROM partes WHERE cod_parte = 624;-- manipule los datos obtenidos aquí...

END;

Procesamiento de transacciones:Se pueden emplear los comandos COMMIT, ROLLBACK y SAVEPOINT para el procesamiento de las transacciones.

3.3. Uso de funciones de SQL.Las funciones que se pueden referenciar en un comando DML pueden ser de estos tipos:• Numéricas (SQRT, ROUND, POWER...)• Caracter (LENGTH,UPPER...)• Fecha (ADD_MONTHS, MONTHS_BETWEEN...)• Grupo (AVG, MAX, COUNT...)Por fuera de los comandos DML (en expresiones, por ejemplo) se permiten todas lasfunciones, exceptuando las de grupo.

Ejemplos:x := SQRT(y);apellido := UPPER(apellido);dif_años := MONTHS_BETWEEN(fecha1, fecha2)/12;

7/16/2019 PL_SQL

http://slidepdf.com/reader/full/plsql-5633867273692 12/3410

4. CODIFICACION DE INSTRUCCIONES DE CONTROL CONDICIONAL E

ITERATIVO

4.1. Objetivos.Al finalizar esta sección, el lector estará en capacidad de:Demostrar el dominio del control condicional en PL/SQL, escribiendo un programaPL/SQL que ejecute instrucciones de manera condicional.Identificar los cuatro tipos de ciclos soportados por PL/SQL.Demostrar el dominio del control iterativo en PL/SQL, escribiendo un programa PL/SQLque emplee ciclos.Diferenciar entre instrucciones GOTO válidas e inválidas.

Identificar tres usos para las etiquetas de PL/SQL.

4.2. Comparaciones lógicas.Las comparaciones lógicas son la base del control condicional en PL/SQL. Los resultadosde estas comparaciones son siempre TRUE, FALSE o NULL.

Comparaciones con valores nulos.• Cualquier cosa comparada con NULL da NULL.• Un NULL en una expresión hace que dicha expresión valga NULL (excepto en la

concatenación).

Ejemplos:5 + NULL -- retorna NULL'PL/' || NULL || 'SQL' -- retorna PL/SQL

Comportamiento de los operadores booleanos: AND, OR, NOT. AND TRUE FALS

E

NULL OR TRUE FALS

E

NULL NOT

TRUE T F N TRUE T T T TRUE F

FALS

E

F F F FALS

E

T F N FALS

E

T

NULL N F N NULL T N N NULL N

4.3. Uso del IF-THEN-ELSE.SINTAXIS:IF <condición> THEN

<secuencia de instrucciones>[ELSIF <condición> THEN

<secuencia de instrucciones>]-- se pueden colocar más ELSIF[ELSE

<secuencia de instrucciones>]

7/16/2019 PL_SQL

http://slidepdf.com/reader/full/plsql-5633867273692 13/3411

END IF;

Notas:

• Las condiciones deben evaluar a un valor booleano (TRUE, FALSE, NULL)• Si la condición es verdadera, la secuencia de instrucciones asociada se ejecuta; de lo

contrario, no.• A lo más una secuencia de instrucciones se ejecuta.

Ejemplo:DECLAREpapeles NUMBER(7);

BEGINSELECT COUNT(*) INTO papeles FROM actuaciones

WHERE cod_actor = &&actor AND activo = 'SI';

IF papeles > 90 THENUPDATE actor SET calidad_actor = 'Tiempo de OSCAR'WHERE cod_actor = &&actor;

ELSIF papeles > 75 THENUPDATE actor SET calidad_actor = 'Telenovelero'WHERE cod_actor = &&actor;

ELSEUPDATE actor SET calidad_actor = 'Mesero'WHERE cod_actor = &&actor;

END IF;

COMMIT;END;

Evite la trampa del nulo cuando codifique instrucciones IF-THEN-ELSE.BLOQUE 1 BLOQUE 2

IF a >= b THENhaga_esto;

ELSEhaga_aquello;

END IF;

IF b > a THENhaga_aquello;

ELSEhaga_esto;

END IF;

• Dado cualquier par de valores no nulos para a y b, ¿Bloque 1 y Bloque 2 hacen lomismo?

• ¿Qué ocurre si a ó b (o las dos) son NULL?

7/16/2019 PL_SQL

http://slidepdf.com/reader/full/plsql-5633867273692 14/3412

LABORATORIO CAPITULO 4 - PARTE 1

Emplee las descripciones de tablas dadas para escribir un programa PL/SQL que solucioneel problema mostrado abajo. Ensaye el bloque ejecutándolo desde SQL*Plus.

Obtenga un número de pedido del operador y encuentre el COD_PRODUCTO asociado.Busque en la tabla INVENTARIO. Si el producto está "EN EXISTENCIA", coloque unafecha en la FECHA_ENTREGA asociada al pedido, la cual debe estar 7 días después de lafecha actual (SYSDATE + 7).

Si el producto está "PEDIDO", coloque una fecha en la FECHA_ENTREGA asociada al pedido, la cual debe estar 1 mes después de la fecha actual(ADD_MONTHS(SYSDATE,1)).

Si el producto es un "PEDIDO ESPECIAL", coloque una fecha en laFECHA_ENTREGA asociada al pedido, la cual debe estar 2 meses después de la fecha

actual (ADD_MONTHS(SYSDATE,2)) y rellene el pedido especial insertando una fila enla tabla PEDIDOS_ESPECIALES. Use el NUM_PED de la tabla PEDIDOS_CLI.Emplee la cantidad estándar de pedido (CANT_STD_PED) en el pedido.

TABLA INVENTARIO

NUMBER(6) CHAR(30) CHAR(20) NUMBER(3)COD_PRODUCTO DESCRIP_PROD ESTADO CANT_STD_PED------------ ----------------- ---------------- ------------

1 Chaqueta estilo 1 EN EXISTENCIA 1002 Chaqueta estilo 2 PEDIDO 2003 Chaqueta estilo 3 PEDIDO ESPECIAL 300

TABLA PEDIDOS_CLI

NUMBER(12) NUMBER(6) DATENUM_PED COD_PRODUCTO FECHA_ENTREGA------------- ------------- -------------

1 12 13 24 15 26 3

TABLA PEDIDOS_ESPECIALES

NUMBER(12) NUMBER(6) NUMBER(3)NUM_PED COD_PRODUCTO CANTIDAD------------ ------------- -------------

 No olvide colocar lo siguiente al final del bloque PL/SQL:

./

7/16/2019 PL_SQL

http://slidepdf.com/reader/full/plsql-5633867273692 15/3413

Esto es necesario para que el bloque se ejecute.

Las instrucciones del SQL*Plus (si coloca alguna) deben ir por fuera del bloque PL/SQL.

7/16/2019 PL_SQL

http://slidepdf.com/reader/full/plsql-5633867273692 16/3414

4.4. Uso de ciclos repetitivos.Existen 4 tipos diferentes de ciclos repetitivos:• Ciclos simples• Ciclos FOR numéricos• Ciclos WHILE

• Ciclos FOR de cursor 

4.4.1. Ciclos simples.

SINTAXIS:LOOP

<secuencia de instrucciones>END LOOP; -- este es un ejemplo de ciclo infinito

Cualquier tipo de ciclo se abandona de forma inmediata con la orden EXIT.

SINTAXIS:

EXIT [WHEN <condición> ]; -- para evitar el ciclo infinito

Ejemplos:DECLAREcont NUMBER(3) :=0;BEGINLOOP

INSERT INTO LOG VALUES (cont, 'ciclos realizados');cont := cont + 1;IF cont = 500

EXIT;END IF;

END LOOP;END;

DECLAREcont NUMBER(3) := 0;BEGINLOOP

UPDATE tabla1 SET comentario = 'ACTUALIZADA'WHERE columna = cont;cont := cont + 1;EXIT WHEN cont = 100;

END LOOP;END;

4.4.2. Ciclos FOR numéricos.

SINTAXIS:FOR <índice> IN [ REVERSE ] <entero>..<entero> LOOP<secuencia de instrucciones>

END LOOP;

El índice del ciclo toma cada valor del rango, uno a la vez, en orden ascendente odescendente.

Ejemplo:

7/16/2019 PL_SQL

http://slidepdf.com/reader/full/plsql-5633867273692 17/3415

BEGINFOR i IN 1..500 LOOP

INSERT INTO temp (col1, mensaje)VALUES (i, 'No debo dormirme en clase.');

END LOOP;END;

Acerca del índice:Es implícitamente de tipo NUMBER.Sólo está definido dentro del ciclo.El índice se puede referenciar en expresiones, pero su valor no puede ser cambiado.

Ejemplos:DECLAREíndice CHAR(20) := 'Pedro Pechugas';BEGINFOR índice IN REVERSE 21..30 LOOP -- redeclara a índice

INSERT INTO TEMP (col1)VALUES (índice); -- inserta los números del 30 al 21

END LOOP;END;

...FOR i IN 1..256 LOOP

x := x + i; -- legali := i + 5; -- ilegal

END LOOP;...

4.4.3. Ciclos WHILE.

SINTAXIS:WHILE <condición> LOOP

<secuencia de instrucciones>END LOOP;

• La condición puede ser cualquier condición legal PL/SQL (debe retornar TRUE,FALSE o NULL).

• La secuencia de instrucciones será repetida mientras la condición sea evaluada comoTRUE.

Ejemplo:DECLAREcont NUMBER(3) :=0;BEGIN

WHILE cont < 500 LOOPINSERT INTO temp (col1, mensaje)VALUES (cont, 'Bueno, tal vez podría dormir un poco.');cont := cont +1;

END LOOP;END;

4.5. Uso del GOTO y las etiquetas.

SINTAXIS:

7/16/2019 PL_SQL

http://slidepdf.com/reader/full/plsql-5633867273692 18/3416

<<nombre_etiqueta>>...GOTO nombre_etiqueta;

¡OJO! No todos los GOTOs son legales! (Un GOTO sólo se puede hacer a una etiquetaque esté antes de dicho GOTO en el programa; en otras palabras, no se puede hacer GOTO hacia adelante).

USO DE LAS ETIQUETAS.• Se pueden usar para etiquetar los bloques, con el fin de diferenciar los BEGINs y los

ENDs (útil en programas largos):<<etiqueta>>[DECLARE-- declaraciones ]

BEGIN-- código ejecutable

[EXCEPTION-- manejadores de excepción ]

END etiqueta; -- debe incluirse aquí el nombre de la etiqueta

• Los bloques también se pueden etiquetar para permitir que una variable que resultaríaescondida por el nombre de una columna se pueda referenciar.

<<muestra>>DECLARE

deptno NUMBER := 20;BEGIN

UPDATE emp SET sal = sal * 1.1WHERE deptno = muestra.deptno;COMMIT;

END muestra;

• Los bloques y ciclos también se pueden etiquetar para referenciar un objeto que deotra manera no sería visible a causa de las reglas de alcance.

<<ciclo_cálculo>>FOR i IN 1..10 LOOP

<instrucciones...>DECLARE

i NUMBER := 0;BEGIN

INSERT INTO temp (col1, col2, mensaje)VALUES (i, ciclo_cálculo.i, 'COMPLETO');

END;

END LOOP ciclo_cálculo; -- debe incluirse el nombre del ciclo aquí

• Los EXITs también se pueden etiquetar para especificar salidas de ciclos másexternos.

...<<ciclo_externo>> WHILE a>b LOOPb := b+1;<<ciclo_interno>> WHILE b>c LOOP

7/16/2019 PL_SQL

http://slidepdf.com/reader/full/plsql-5633867273692 19/3417

c := c+2;EXIT ciclo_externo WHEN c > 200;

END LOOP ciclo_interno;END LOOP ciclo_externo;...

7/16/2019 PL_SQL

http://slidepdf.com/reader/full/plsql-5633867273692 20/3418

LABORATORIO CAPITULO 4 - PARTE 2

Emplee las descripciones de tablas dadas para escribir un programa PL/SQL que solucioneel problema mostrado abajo. Ensaye el bloque ejecutándolo desde SQL*Plus.

Escriba un programa PL/SQL que tenga un ciclo externo y uno interno. El externo itera 5veces, el interno 4.

En el ciclo externo, inserte una fila en la tabla TEMP que tenga el índice del ciclo enCOL1, NULL en COL2 y el mensaje 'Ciclo externo' en MENSAJE.

En el ciclo interno, inserte una fila en la tabla TEMP que contenga el índice del cicloexterno en COL1, el índice del ciclo interno en COL2, y el mensaje 'Ciclo interno' enMENSAJE.

TABLA TEMP

NUMBER(9,4) NUMBER(9,4) CHAR(55)COL1 COL2 MENSAJE

------------ -------------- -------------

7/16/2019 PL_SQL

http://slidepdf.com/reader/full/plsql-5633867273692 21/3419

5. DECLARACION Y USO DE CURSORES

5.1. Objetivos.

Al finalizar esta sección, el lector estará en capacidad de:• Identificar los dos tipos de cursores soportados por PL/SQL.• Esquematizar los pasos para usar cursores explícitos en bloques PL/SQL.• Mostrar el dominio de los cursores, escribiendo programas PL/SQL que los usen.• Usar los atributos del cursor implícito.

5.2. ¿Qué es un cursor?Un cursor es un área de memoria que se reserva para efectuar una serie de operaciones

sobre una serie de filas, en los casos en que un SELECT retorna más de una fila.

Todo comando DML de SQL (en particular, todo INSERT, UPDATE, DELETE,SELECT...INTO, COMMIT y ROLLBACK) que sea procesado por PL/SQL tieneasociado un cursor.

Existen dos tipos de cursores:• EXPLICITOS: Se usan en SELECTs que retornan más de una fila.• IMPLICITOS: Todos los INSERTs, UPDATEs, DELETEs y los SELECTs que

retornan una sola fila hacen uso del cursor implícito.

5.3. Uso de cursores explícitos.El conjunto de filas que retorna una consulta puede constar de ninguna, una o varias filas.Esto depende del número de filas que satisfagan la condición de búsqueda.

Cuando se sabe que una consulta puede retornar múltiples filas, se puede definir un cursor explícito para:• Procesar, además de la primera fila retornada, todas las que le sigan.• Tener presente qué fila es la que se está procesando.

Los pasos para el uso de un cursor explícito son:• Declarar el cursor 

• Abrir el cursor • Extraer los datos del cursor • Cerrar el cursor 

DECLARACION DE UN CURSOR La declaración del cursor asocia su nombre con una instrucción SELECT. Este SELECTno debe tener cláusula INTO.Los cursores tienen alcance, así como las variables.

7/16/2019 PL_SQL

http://slidepdf.com/reader/full/plsql-5633867273692 22/3420

SINTAXIS:DECLARE

CURSOR <nombre_cursor >IS SELECT ... ;

Ejemplo:DECLARE

x NUMBER(7,2);total NUMBER(5);lim_inf CONSTANT NUMBER(4) := 1200;CURSOR c1 IS SELECT ename FROM emp

WHERE sal > lim_inf;BEGIN...

APERTURA DE UN CURSOR La apertura de un cursor procesa la orden SELECT, asigna los recursos ORACLE y elárea de memoria necesarios para almacenar temporalmente el resultado de este SELECT,

y almacena el resultado en el área de memoria.

SINTAXIS:OPEN <nombre_cursor >;

EXTRACCION DE DATOS DE UN CURSOR Se hace mediante el comando FETCH:FETCH <nombre_cursor > INTO <var1, var2, ...>;

Debe haber exactamente una variable en el INTO por cada columna que traiga elSELECT. La primera columna quedará en var1, la segunda en var2, y así sucesivamente.

CLAUSURA DE UN CURSOR La clausura de un cursor marca los recursos usados por el cursor como reutilizables. Nose pueden extraer filas de un cursor cerrado.

SINTAXIS:CLOSE <nombre_cursor >;ATRIBUTOS DE LOS CURSORES EXPLICITOS

%NOTFOUND toma el valor TRUE si el FETCH anterior no retornó fila alguna.LOOP

FETCH cur1 INTO nombre, sueldo;EXIT WHEN cur1%NOTFOUND;

-- sigue el procesamiento de los datosEND LOOP;

%FOUND toma el valor TRUE si el FETCH anterior retornó una fila.FETCH cur1 INTO nombre, sueldo;WHILE cur1%FOUND LOOP

-- sigue el procesamiento de los datosFETCH cur1 INTO nombre, sueldo;

7/16/2019 PL_SQL

http://slidepdf.com/reader/full/plsql-5633867273692 23/3421

END LOOP;

%ROWCOUNT toma el valor de las filas a las que se les ha hecho FETCH hasta elmomento.LOOP

FETCH cur1 INTO nombre, sueldo;EXIT WHEN (cur1%NOTFOUND) OR (cur1%ROWCOUNT > 10);-- sigue el procesamiento de los datos

END LOOP;

%ISOPEN toma el valor TRUE si el cursor asociado está abierto.IF cur1%ISOPEN THEN

FETCH cur1 INTO nombre, sueldo;ELSE

OPEN cur1;END IF;

Ejemplo completo del uso de un cursor:DECLARElimite NUMBER(4):=0;nombre emp.ename%TYPE;sueldo emp.sal%TYPE;CURSOR cur1 IS SELECT ename, sal FROM emp

WHERE sal > limite;BEGIN

limite := 1200;OPEN cur1; -- emplea 1200 como límiteLOOP

FETCH cur1 INTO nombre, sueldo;EXIT WHEN cur1%NOTFOUND;INSERT INTO otra_tabla VALUES (nombre, sueldo);

END LOOP;CLOSE cur1;COMMIT;

END;

Si el cursor posee en su declaración variables que cambien su valor en el transcurso del programa, el hecho de cerrar el cursor y volverlo a abrir hace que el SELECT se vuelva aejecutar con el nuevo valor de la variable.

Ejemplo:DECLARE

total_bonos NUMBER(8,2) := 0;minimo emp.sal%TYPE := 1000; -- para iniciarvalor_bono emp.sal%TYPE;

CURSOR bono ISSELECT sal*.10 FROM emp WHERE sal > minimo;BEGIN

OPEN bono; -- usa un mínimo de 1000LOOP

FETCH bono INTO valor_bono;EXIT WHEN bono%NOTFOUND;total_bonos := total_bonos + valor_bono;IF total_bonos > 2000 THEN

/* subir el mínimo e intentarlo de nuevo */

7/16/2019 PL_SQL

http://slidepdf.com/reader/full/plsql-5633867273692 24/3422

minimo := minimo + 500;total_bonos := 0; -- poner a ceros el totalCLOSE bono;OPEN bono; -- reabre el cursor con el minimo nuevo

END IF;END LOOP;

END;

Si se desea referenciar por algún motivo la fila de la tabla que está siendo procesada, seemplea la cláusula WHERE CURRENT OF. En este caso, el cursor debe ser declaradocon la cláusula FOR UPDATE OF.

Ejemplo:DECLARECURSOR cur1 IS SELECT ename, sal FROM emp

FOR UPDATE of sal;nombre emp.ename%TYPE;sueldo emp.sal%TYPE;BEGIN

OPEN cur1;LOOPFETCH cur1 INTO nombre, sueldo;EXIT WHEN cur1%NOTFOUND;IF sueldo > 3000 THENDELETE FROM emp WHERE CURRENT OF cur1;END IF;...

END LOOP;...

5.4. Ciclos FOR de cursor.Los ciclos FOR de cursor son similares a los ciclos FOR numéricos:• Mientras que los ciclos FOR numéricos precisan de un rango numérico para funcionar,

los ciclos FOR de cursor emplean un subconjunto de filas de la tabla determinado por el cursor.

• Un ciclo FOR numérico se ejecuta una vez para cada valor del rango numérico. Unciclo FOR de cursor se ejecuta una vez para cada fila traída por el cursor.

SINTAXIS:FOR <nombre_registro> IN <nombre_cursor >

--- lista de comandos a repetirEND LOOP;

<nombre_registro > se declara de manera implícita como:

nombre_registro nombre_cursor%ROWTYPE;Para referenciar alguno de sus componentes, se emplea la notaciónnombre_registro.columna.

El funcionamiento es el siguiente:• Cuando se inicia el ciclo, se hace un OPEN implícito del cursor.• Para cada fila del cursor se hace un FETCH implícito.

7/16/2019 PL_SQL

http://slidepdf.com/reader/full/plsql-5633867273692 25/3423

• Cuando no quedan más filas por traer, el ciclo finaliza y se efectúa un CLOSEimplícito del cursor.

Ejemplo:DECLARE

límite NUMBER(4) := 0;

total NUMBER(9,2) := 0;CURSOR cur1 IS SELECT ename, sal FROM emp

WHERE sal > límite;BEGIN

límite := 1200;-- a continuación se hace un OPEN implícitoFOR fila IN cur1 LOOP

-- aquí se efectúa un FETCH implícitoINSERT INTO otra_tabla

VALUES (fila.ename, fila.sal);total := total + fila.sal;

END LOOP; -- sa hace aquí un CLOSE implícito...

END;

USO DE PARAMETROS EN LOS CURSORESDECLARE

CURSOR <nombre_cursor > [(nombre_parámetro tipo)]IS SELECT... ;

Ejemplo:DECLARE

CURSOR cur2 (valor NUMBER) ISSELECT ename FROM emp WHERE sal > valor;

BEGINOPEN cur2 (1200)...

END;

5.5. Uso del cursor implícito.Toda instrucción DML de SQL (INSERT, UPDATE, DELETE, SELECT...INTO) queno tenga un cursor explícito asociado con ella tiene asociado el cursor implícito, conocidotambién como el cursor SQL.

Para este cursor no tienen sentido las operaciones de OPEN, FETCH ni CLOSE. Todoslos atributos de cursor son válidos en su contexto.

• SQL%NOTFOUND retorna TRUE si la instrucción SQL más recientemente ejecutadano afectó ninguna fila.

• SQL%FOUND retorna TRUE si la instrucción SQL más recientemente ejecutadaafectó una o más filas.

• SQL%ROWCOUNT retorna el número de filas afectadas por un DELETE o unUPDATE, el número de filas insertadas, o el número de filas retornadas por unSELECT...INTO.

7/16/2019 PL_SQL

http://slidepdf.com/reader/full/plsql-5633867273692 26/3424

• SQL%ISOPEN siempre retorna FALSE.

7/16/2019 PL_SQL

http://slidepdf.com/reader/full/plsql-5633867273692 27/3425

LABORATORIO CAPITULO 5

Escriba un programa PL/SQL que solucione el problema mostrado abajo. Ensaye el bloque ejecutándolo desde SQL*Plus.

Obtenga un número n del operador, usando una variable &.

Usando un ciclo simple, obtenga el nombre y sueldo de los empleados con los n salariosmás altos de la empresa. Estos nombres y salarios se pueden encontrar en la tabla EMP.Almacénelos en una tabla llamada SALARIOS_ALTOS, con columnas NOMBRECHAR(20) y SALARIO NUMBER(7,2).

Repita este punto usando un ciclo FOR de cursor.

7/16/2019 PL_SQL

http://slidepdf.com/reader/full/plsql-5633867273692 28/3426

6. MANEJO DE ERRORES EN PL/SQL

6.1. Objetivos.

Al finalizar esta sección, el lector estará en capacidad de:• Identificar los dos tipos de manejo de excepciones en PL/SQL.• Identificar las funciones de PL/SQL que dan información acerca de los errores.• Escribir bloques de PL/SQL que contengan instrucciones para manejo de excepciones.

6.2. ¿Qué son las excepciones?En PL/SQL, los errores se denominan excepciones. Cuando una excepción es disparada(ocurre un error), el flujo del procesamiento salta a los manejadores de excepciones.

Un manejador de excepción es una secuencia de instrucciones que se procesan cuandoocurre determinado error. Cuando termina el manejador de excepción, el flujo del programa abandona el bloque.

TIPOS DE EXCEPCIONES:

• Excepciones internas predefinidas: Se corresponden con aproximadamente 20errores ORACLE comunes. PL/SQL las dispara automáticamente en respuesta a unerror ORACLE.

• Excepciones definidas por el usuario: Deben ser declaradas, y se deben disparar manualmente.

EXCEPCIONES INTERNAS PREDEFINIDAS.Todo error ORACLE dispara una excepción automáticamente; algunas de las máscomunes tienen nombres.

Ejemplos:TOO_MANY_ROWS (ORA-01427):A single row SELECT returned more than one row

NO_DATA_FOUND (ORA-01403):A single row SELECT returned no data

INVALID_CURSOR (ORA-01001):Invalid cursor was specified

VALUE_ERROR (ORA-06502):Arithmetic, numeric, string, conversion, or constraint error occurred.ZERO_DIVIDE (ORA-01476):Attempted to divide by zero.

DUP_VAL_ON_INDEX (ORA-00001)Attempted to insert a duplicate value into a column that has a uniqueindex specified.

7/16/2019 PL_SQL

http://slidepdf.com/reader/full/plsql-5633867273692 29/3427

CURSOR_ALREADY_OPEN (ORA-06511)Attempted to open an already open cursor.

DECLARACION DE LOS MANEJADORES DE EXCEPCIONWHEN <nombre_excepción> [ OR <nombre_excepción> ... ] THEN

<secuencia de instrucciones>...[ WHEN OTHERS THEN -- si se usa, debe ser el último manejador

<secuencia de instrucciones> ]

Ejemplo:DECLAREnum_emp emp.empno%TYPE;

BEGINSELECT empno INTO num_emp FROM emp

WHERE ename = 'BLAKE';INSERT INTO temp (col1, mensaje)

VALUES (num_emp, 'Código de Blake');

DELETE FROM emp WHERE ename = 'BLAKE';

EXCEPTIONWHEN NO_DATA_FOUND THEN

ROLLBACK;INSERT INTO temp (mensaje)

values ('No se encontró a BLAKE');COMMIT;

WHEN TOO_MANY_ROWS THENROLLBACK;INSERT INTO temp (mensaje)

values ('Se halló más de un BLAKE');COMMIT;

WHEN OTHERS THEN

ROLLBACK;

END;

EXCEPCIONES DEFINIDAS POR EL USUARIO.

Ejemplo:DECLAREx NUMBER;excep EXCEPTION; -- un tipo nuevo de objeto

Cómo dispararla:RAISE excep;

• Una vez que una excepción es disparada manualmente, se la trata exactamente de lamisma manera que a una excepción predefinida.

• Las excepciones tienen alcance, como las variables.• Las excepciones definidas por el usuario se chequean manualmente y luego se

disparan, si es necesario.

Ejemplo:

7/16/2019 PL_SQL

http://slidepdf.com/reader/full/plsql-5633867273692 30/3428

DECLAREnombre emp.ename%TYPE := 'BLAKE';proy_asig NUMBER;pocos_proy EXCEPTION;

BEGIN-- obtener número de proyectos asignados a Blake

...IF proy_asig < 3 THEN

RAISE pocos_proy;END IF;

EXCEPTIONWHEN pocos_proy THEN

INSERT INTO tempVALUES (nombre, proy_asig, 'Menos de 3 proyectos!');COMMIT;

...END;

PROPAGACION DE LAS EXCEPCIONES Procedimiento:• Al dispararse la excepción, se busca un manejador en el bloque actual. Si no se

encuentra, se sigue con el paso 2.• Si este bloque tiene un padre, se busca el manejador en el padre.• Se repiten los pasos 1 y 2 hasta que se llega al bloque raíz, o se encuentra un

manejador.- Si se llega al bloque raíz y no se encuentra un manejador, la excepción se le pasa

al ambiente que llama al PL/SQL (SQL*Plus, SQL*Forms, etc.)- Si se encuentra un manejador, se ejecuta. Cuando termina, el control pasa al

 bloque padre del bloque donde se encontró el manejador, o al ambiente si el bloque donde se halló el manejador es el raíz.

• Puede haber únicamente un manejador activo al tiempo por bloque.• Si se dispara una excepción en un manejador, la búsqueda de un manejador para esta

nueva excepción se inicia en el bloque padre del bloque actual.

Ejemplo:

BEGIN...

BEGINIF X=1 THEN

RAISE A;

ELSIF X=2 THENRAISE B;

ELSERAISE C;

EXCEPTIONWHEN A THEN...

END;...

7/16/2019 PL_SQL

http://slidepdf.com/reader/full/plsql-5633867273692 31/3429

EXCEPTIONWHEN B THEN...

END;

En este ejemplo, en la ejecución del bloque más interno:• Si se dispara la excepción A, se encuentra un manejador en el mismo bloque. Este seejecuta y el flujo del programa continúa en el bloque exterior.

• Si se dispara la excepción B, ésta se propaga al bloque exterior, donde es manejada.Una vez ejecutado el manejador, el control se le devuelve al ambiente.

• Si se dispara la excepción C, no se encuentra manejador alguno, y el programa finalizacon un error en tiempo de ejecución.

OTROS USOS DE RAISERAISE, por sí solo, vuelve a disparar la excepción actual (como si ésta se propagara).Esta modalidad de RAISE sólo se puede emplear en un manejador de excepción.

COMO PONERLE NOMBRE A LOS ERRORES DE ORACLELas excepciones sólo pueden ser manejadas por nombre (no por código ORACLE deerror). Para colocarle un nombre a un error de ORACLE, de manera que se le pueda programar un manejador, se emplea la cláusula EXCEPTION_INIT:

PRAGMA EXCEPTION_INIT(<nombre_de_usuario>, <código_error_ORACLE>);

Ejemplo:DECLARE

abrazo_mortal EXCEPTIONPRAGMA EXCEPTION_INIT(abrazo_mortal, -60);

6.3. Funciones para reporte de errores.Estas funciones dan información acerca de la excepción que se está manejando endeterminado momento. Son especialmente útiles en el manejador OTHERS.

SQLCODE: Retorna el código de error ORACLE asociado con la excepción, o 1 si laexcepción es definida por el usuario.

SQLERRM: Retorna el error relacionado con el valor actual de SQLCODE. Puedeusarse también como argumento cualquier código de error ORACLE.

• Si no hay excepción activa, SQLCODE retorna 0, y SQLERRM retorna 'Normal,successful completion'.

• SQLCODE y SQLERRM no se pueden usar en instrucciones SQL.

Ejemplo:DECLARE

sqlcode_val NUMBER;sqlerrm_val CHAR(55);

7/16/2019 PL_SQL

http://slidepdf.com/reader/full/plsql-5633867273692 32/3430

BEGIN...EXCEPTION

WHEN OTHERS THENsqlcode_val:=SQLCODE;

-- SQLCODE no se puede insertar directamente

sqlerrm_val:=SUBSTR(SQLERRM,1,55);-- SQLERRM no se puede insertar directamente-- Debe usarse SUBSTR para garantizar que la-- cadena retornada cabe en-- la variable de destino.

INSERT INTO temp (col1, mensaje)VALUES(sqlcode_val, sqlerrm_val);

END;

7/16/2019 PL_SQL

http://slidepdf.com/reader/full/plsql-5633867273692 33/3431

LABORATORIO CAPITULO 6

Emplee las descripciones de tablas dadas para escribir un programa PL/SQL que solucioneel problema mostrado abajo. Ensaye el bloque ejecutándolo desde SQL*Plus.

La tabla ACCION define un conjunto de acciones que se realizarán sobre la tablaCUENTAS. Las acciones (almacenadas en la columna TIPO) puede ser 'I' para insertar una cuenta nueva, o 'A' para actualizar una cuenta existente. Por ejemplo, si una fila enACCION se lee 6, 'I', 2099; debe crearse la cuenta 6 con $2,099 como balance inicial. Sien esta fila de muestra hubiera habido una 'A' en lugar de una 'I', se tendría que actualizar la cuenta 6, y colocar el nuevo balance en $2,099

Escriba un bloque PL/SQL que tome cada fila de ACCION (ayuda: aquí se puede usar uncursor) y ejecute las acciones especificadas.

Si se intenta insertar una fila que ya exista, actualícela. La excepción interna

DUP_VAL_ON_INDEX se disparará, de manera que su bloque debe incluir un manejador que efectúe la actualización. Si se intenta actualizar una fila que no exista, insértela(¿Cómo se sabe que no se actualizó ninguna fila?)

TABLA CUENTAS

*INDICE UNICO*NUMBER(4) NUMBER(11,2)NUM_CUENTA BALANCE----------- ------------

1 10002 20003 1500

4 65005 500

TABLA ACCION

NUMBER(4) CHAR(1) NUMBER(11,2)NUM_CUENTA TIPO VALOR_NUEVO---------- -------- ------------

3 A6 I7 A1 I

7/16/2019 PL_SQL

http://slidepdf.com/reader/full/plsql-5633867273692 34/34

LABORATORIO OPCIONAL CAPITULO 6

Pida al usuario un número de departamento, y empleando un cursor, obtenga el sueldo,comisión y nombre de cada empleado del departamento. Esta información se inserta en lascolumnas COL1, COL2 y MENSAJE de la tabla TEMP usada en la segunda parte del

laboratorio del capítulo 4.

Sin embargo, si un empleado de ese departamento tiene comisión nula, dispare unaexcepción definida por el usuario. En el manejador deshaga primero todos los INSERTshechos. Luego cierre y reabra el cursor, insertando esta vez únicamente el sueldo y elnombre de cada empleado en las columnas COL1 y MENSAJE de la tabla TEMP.