Manual PLSQL Basico
Manual PLSQL Basico
Manual PLSQL Basico
Básico
Prólogo
PL/SQL, bajo este nombre se esconde el Lenguaje de manipulación de
datos propietario de Oracle. Conceptualmente, Oracle lo define como
una extensión procedimental del SQL… en realidad, y para entenderlo
mejor, se trata de un potente lenguaje de acceso a Bbdd, mediante el cual
podemos estructurar y controlar las sentencias SQL que definamos para
nuestra Bbdd.
PL/SQL sigue la filosofía de los modernos lenguajes de programación,
es decir, permite definir y manipular distintos tipos de datos, crear
procedimientos, funciones, contempla recursividad, etc… Quizás la
diferencia más importante, y algo que debemos tener siempre muy en
cuenta, es que la eficiencia de un programa en PL/SQL se mide sobre
todo por la eficiencia de los accesos a Bbdd.
La consecuencia más inmediata de lo dicho anteriormente, es que para
poder programar de manera óptima en PL/SQL, se debe tener un
dominio notable del propio SQL; cumpliendo esta premisa, y algunas
otras que veremos más adelante, obtendremos una mejora sustancial en
nuestras aplicaciones que interactuen con Bbdd.
ÍNDICE
INTRODUCCIÓN ................................................................. 3
Prólogo............................................................................................................... 3
ÍNDICE .............................................................................. 4
FICHA INFORMATIVA DEL MÓDULO. .................................. 6
Nombre .............................................................................................................. 6
Meta .................................................................................................................... 6
Requisitos del alumno ...................................................................................... 6
Bibliografía......................................................................................................... 6
1 UNIDAD 4:INTRODUCCIÓN A PL/SQL ............................ 7
Objetivo general de la unidad ......................................................................... 7
Objetivos específicos........................................................................................ 7
Contenidos......................................................................................................... 7
Cuaderno de notas............................................................................................ 8
1.1 Introducción............................................................................................... 10
1.2 Tipos de Datos........................................................................................... 16
1.3 Declaraciones ............................................................................................. 22
1.4 Ámbito y Visibilidad.................................................................................. 32
1.5 Asignaciones............................................................................................... 34
1.6 Expresiones y Comparaciones................................................................. 35
1.7 Funciones Soportadas ............................................................................... 39
2 UNIDAD 5:ESTRUCTURAS DE CONTROL ......................... 41
Objetivo general de la unidad ....................................................................... 41
Objetivos específicos...................................................................................... 41
Contenidos....................................................................................................... 41
Cuaderno de notas.......................................................................................... 42
2.1 Introducción............................................................................................... 44
2.2 Control Condicional.................................................................................. 44
2.3 Control Iterativo ........................................................................................ 47
2.4 Control Secuencial..................................................................................... 54
3 UNIDAD 6:INTERACCIÓN CON ORACLE ......................... 58
Objetivo general de la unidad ....................................................................... 58
Nombre
PL/SQL Básico
Meta
Que el Alumno adquiera los conocimientos básicos sobre estructuras
de datos y sentencias, necesarios para el desarrollo de aplicaciones que
llamen a subprogramas PL/SQL en el acceso a Bbdd.
Bibliografía
PL/SQL User’s Guide and Reference, y varios artículos sobre
PL/SQL obtenidos de Internet.
1 UNIDAD 4:INTRODUCCIÓN A
PL/SQL
Objetivos específicos
Conocer los tipos de datos soportados por PL/SQL, así como la
sintaxis básica de las sentencias que utiliza.
Contenidos
Introducción
Tipos de Datos
Declaraciones
Ámbito y Visibilidad
Asignaciones
Expresiones y Comparaciones
Funciones Soportadas
Cuaderno de notas
PL/SQL Básico
Unidad 4: Introducción a PL/SQL
1.1 Introducción
Cuando escribimos un programa en PL/SQL, utilizamos un conjunto
específico de caracteres. El conjunto de caracteres soportado es el
siguiente:
• Los caracteres mayúsculas y minúsculas A … Z, a … z
• Los números 0 … 9
• Tabulaciones, espacios y retornos de carro
• Los símbolos ( ) + - * / < > = ¡ ~ ; : . ‘ @ % , “ # $ ^ & _ |
{}¿[]
PL/SQL no es ‘case sensitive’, por lo tanto no distingue entre
mayúsculas y minúsculas, excepto para un par de casos que
comentaremos más adelante.
IF x>y THEN
max:=x;
ELSE
max:=y;
END IF;
1.1.2 Delimitadores
Un delimitador es un símbolo simple o compuesto, que tiene un
significado especial en PL/SQL.
Veamos cada uno de los tipos.
1.1.2.1 Símbolos simples
La lista y significado de los símbolos simples son los siguientes:
+ Operador de suma
% Indicador de Atributo
‘ Carácter delimitador de String
. Selector
/ Operador de división
( Expresión o delimitador de lista
) Expresión o delimitador de lista
: Indicador de variable host
, Separador de Items
* Operador de multiplicación
“ Delimitador de identificadores
= Operador relacional
< Operador relacional
> Operador relacional
@ Indicador de acceso remoto
; Terminador de sentencia
- Resta/Operador de negación
1.1.3 Identificadores
Los identificadores se utilizan para dar nomenclatura a unidades e
items de un programa PL/SQL, el cual puede incluir constantes,
variables, excepciones, cursores, cursores con variables, subprogramas y
packages.
Un identificador consiste en una letra seguida, de manera opcional, de
más letras, números, signos de dólar, underscores, y signos numéricos.
Algunos caracteres como % - / y espacios son ilegales.
Ejemplo:
mi_variable -- Identificador legal
mi variable -- Identificador Ilegal
mi-variable -- Identificador Ilegal
Se pueden usar mayúsculas, minúsculas, o mezcla de ambas… ya
hemos comentado que PL/SQL no es ‘case sensitive’, con lo cual no las
diferenciará, exceptuando el caso en que estemos ante tratamiento de
Strings, o bien literales de un solo carácter.
DECLARE
end BOOLEAN; -- Ilegal
DECLARE
end_film BOOLEAN; -- Legal
“X+Y”
“ultimo nombre”
“switch on/off”
1.1.4 Literales
Un literal es un valor explícito de tipo numérico, carácter, string o
booleano, no representado por un identificador. El literal numérico 147,
y el literal booleano FALSE, son ejemplos de esto.
1.1.4.1 Literales Numéricos
Podemos utilizar dos clases de literales numéricos en expresiones
aritméticas: enteros y reales.
Un literal Entero, es un número Entero, al que podemos
opcionalmente poner signo. Ejemplos:
30, 6, -14, 0, +32000, …
Un literal Real, es un número Entero o fraccional, con un punto
decimal. Ejemplos son:
6.667, 0.0, -12.0, +86.55, …
PL/SQL considera como reales a los números de este tipo 12.0, 25. ,
aunque tengan valores enteros. Es muy importante tener esto en cuenta,
básicamente porque debemos evitar al máximo trabajar con reales si
podemos hacerlo con enteros, ya que eso disminuye la eficiencia
de nuestro programa.
Los literales numéricos no pueden tener los signos dólar o coma, sin
embargo, pueden ser escritos en notación científica. Ejemplo:
2E5, 1.0E-7, …
1.1.5 Comentarios
El compilador de PL/SQL ignora los comentarios, sin embargo
nosotros no debemos hacerlo. La inserción de comentarios es muy útil a
la hora de entender un programa.
PL/SQL soporta dos tipos de comentarios: los de una línea, y los de
múltiples líneas.
1.1.5.1 Comentarios de una línea
Se definen mediante dos signos menos consecutivos (--), que se ponen
al principio de la línea a comentar… a partir de ahí, y hasta la línea
siguiente, se ignora todo. Ejemplo:
-- Comienzo mi Select
SELECT * FROM mitabla
WHERE mit_mitkey=p_codigo ; -- Solo los de mi código
DECLARE
SUBTYPE Acumulador IS NUMBER;
cantidad NUMBER(7,2);
total Acumulador;
BEGIN
…
total := cantidad;
Bin_Int X X X X X
Char X X X X X X X X
Date X X X
Long X X X
Number X X X X X
Pls_Int X X X X X
Raw X X X
Rowid X X
Varchar2 X X X X X X X X
1.3 Declaraciones
En PL/SQL se pueden declarar tanto constantes como variables;
recordemos que las variables pueden cambiar en tiempo de
ejecución, mientras que las constantes permanecen con el mismo
valor de forma continua.
Se pueden declarar constantes y variables en la parte de declaración de
cualquier bloque PL/SQL, subprograma, o package. Las declaraciones
reservan espacio para un valor en función de su tipo.
DECLARE
emp_rec emp%ROWTYPE;
…
BEGIN
SELECT * INTO emp_rec
FROM emp
WHERE ROWNUM=1;
…
END;
Para referenciar los valores almacenados en un registro, utilizaremos la
notación siguiente:
nombre_registro.nombre_campo
Por ejemplo, en el caso anterior referenciaríamos al campo nombre de
la siguiente manera:
IF emp_rec.emp_nomemp='Perico' THEN …
mi_rec mi_cursor%ROWTYPE;
BEGIN
OPEN mi_cursor;
LOOP
FETCH mi_cursor INTO mi_rec;
EXIT WHEN mi_cursor%NOTFOUND;
IF mi_rec.wages>2000 THEN
INSERT INTO temp VALUES (NULL, mi_rec.wages,
mi_rec.nom_emp);
END IF;
END LOOP;
CLOSE mi_cursor;
END;
1.3.5 Restricciones
PL/SQL no permite referencias de tipo forward, es decir, se debe
crear una variable o constante antes de referenciarla en otras sentencias,
incluyendo las sentencias de tipo declaración. Veamos un ejemplo:
maxi INTEGER := 2*mini; -- No válido…
mini INTEGER := 15;
Sin embargo, PL/SQL sí que permite la declaración de tipo
forward para subprogramas.
Otra restricción de PL/SQL, es que no permite una declaración de
este tipo:
i, j, k SMALLINT; -- No válido…
Debemos declararlo de la siguiente manera:
i SMALLINT;
j SMALLINT;
k SMALLINT;
1.3.7 Sinónimos
Se pueden crear sinónimos para proporcionar transparencia en el
acceso a un esquema remoto de sus tablas, secuencias, vistas,
subprogramas y packages. Sin embargo, y como es lógico, no podemos
crear sinónimos para los objetos declarados en subprogramas o
packages; esto incluye constantes, variables, cursores, cursores con
variables, excepciones y procedures de un package (de forma individual).
1.3.8 Ámbito
En el mismo ámbito, todos los identificadores que se declaren deben
ser únicos. Por lo tanto, e incluso aunque sus tipos difieran, las variables
y parámetros no pueden tener el mismo nombre. Veamos un par de
ejemplos:
DECLARE
id_valido BOOLEAN;
id_valido VARCHAR2(5); -- No válido, nombre repetido…
FUNCTION bonus (id_valido IN INTEGER)
RETURN REAL IS … -- No válido, nombre repetido dos veces..
Veremos en profundidad todo este tema en el apartado dedicado a
Visibilidad.
Ámbito Visibilidad
DECLARE DECLARE
X REAL; X REAL;
BEGIN BEGIN
... ...
X Exterior DECLARE DECLARE
X REAL; X REAL;
BEGIN BEGIN
... ...
END; END;
... ...
END; END;
DECLARE DECLARE
X REAL; X REAL;
BEGIN BEGIN
... ...
X Interior DECLARE DECLARE
X REAL; X REAL;
BEGIN BEGIN
... ...
END; END;
... ...
END; END;
DECLARE
a CHAR;
b REAL;
BEGIN
-- Identificadores accesibles aquí: a (CHAR), b
DECLARE
a INTEGER;
c REAL;
BEGIN
-- Identificadores accesibles aquí: a (INTEGER), b, c
END;
…
END;
Si quisiéramos referenciar a identificadores del mismo ámbito, pero
más externos, deberíamos utilizar etiquetas. Veamos un ejemplo de esto:
<<externo>>
DECLARE
cumple DATE;
BEGIN
DECLARE
cumple DATE;
BEGIN
…
IF cumple = exterior.cumple THEN …
1.5 Asignaciones
Las variables y constantes se inicializan cada vez que se entra en un
bloque o subprograma. Por defecto, las variables se inicializan a NULL,
por lo tanto, a menos que se le asigne expresamente, el valor de una
variable es indefinido. Veamos un caso curioso:
DECLARE
contador INTEGER;
…
BEGIN
contador := contador+1; -- Contador sigue valiendo NULL…
…
END;
Efectivamente, la suma de NULL+1 es siempre NULL, la asignación
debe realizarse de manera expresa. En general, cualquier operación en
la cual uno de los operandos sea NULL, nos devolverá un
NULL… es algo que deberemos tener muy en cuenta.
Lo que siga al operador de asignación, puede ser tanto un valor simple
(literal numérico), como una expresión compleja… lo único que
debemos tener siempre en cuenta es que debe tratarse de un valor del
mismo tipo, o por lo menos convertible de forma implícita.
x y x AND y x OR y NOT x
TRUE TRUE TRUE TRUE FALSE
TRUE FALSE FALSE TRUE
TRUE NULL NULL TRUE
FALSE TRUE FALSE TRUE TRUE
FALSE FALSE FALSE FALSE
FALSE NULL FALSE NULL
NULL TRUE NULL TRUE NULL
NULL FALSE FALSE NULL
NULL NULL NULL NULL
Operador Significado
= Igual a…
<>, !=, ~= Diferente a…
< Menor que…
> Mayor que…
<= Menor o igual a…
>= Mayor o igual a…
1.6.3.5 Operador IN
El operador IN, comprueba si un valor pertenece a un conjunto. El
significado literal sería ‘igual a cualquier miembro de…’.
El conjunto de valores puede contener nulos, pero son ignorados. Por
ejemplo, la siguiente sentencia no borraría los registros de la tabla que
tuvieran la columna nom_emp a null.
DELETE FROM emp WHERE nom_emp IN (NULL, ’PEPE’,
’PEDRO’);
Es más, expresiones del tipo
valor NOT IN conjunto
POWER NLS_UPPER
ROUND NLSSORT
SIGN REPLACE
SIN RPAD
SINH RTRIM
SQRT SOUNDEX
TAN SUBSTR
TANH SUBSTRB
TRUNC TRANSLATE
UPPER
Objetivos específicos
Que el alumno conozca y sepa utilizar en el momento adecuado, todas
las estructuras de control aportadas por PL/SQL.
Contenidos
Introducción
Control Condicional
Control Iterativo
Control Secuencial
Cuaderno de notas
PL/SQL Básico
Unidad 5 Estructuras de Control
T F F
2.2.1 IF-THEN
Es la forma más sencilla de una sentencia IF. Asocia una secuencia de
sentencias a una condición. Veamos un ejemplo:
IF condicion THEN
secuencia_de_sentencias;
END IF;
PL/SQL Básico
Unidad 5: Estructuras de Control
2.2.2 IF-THEN-ELSE
Esta segunda variedad añade la palabra clave ELSE, seguida de un
conjunto de sentencias. Veamos un ejemplo:
IF condicion THEN
secuencia_1;
ELSE
secuencia_2;
END IF;
Si la condición es TRUE, se ejecutará la secuencia de instrucciones 1,
en caso contrario se ejecutará la 2.
Las claúsulas THEN y ELSE pueden incluir sentencias IF, es decir,
podemos agrupar sentencias de tipo IF. Veamos un ejemplo:
IF tipo_transaccion = ‘CR’ THEN
UPDATE cuentas SET balance=balance+credito WHERE…
ELSE
IF nuevo_balance >= balance_minimo THEN
UPDATE cuentas SET balance=balance-debito WHERE…
ELSE
RAISE fondos_insuficientes;
END IF;
END IF;
2.2.3 IF-THEN-ELSIF
Como hemos visto, podemos agrupar sentencias de tipo IF… sin
embargo, nos podemos encontrar el caso en que existan muchas posibles
alternativas a evaluar, y para cada ELSE tendríamos que abrir una
2.3.1 LOOP
Se trata de la variedad más simple de la sentencia LOOP, y se
corresponde con el bucle básico (o infinito), el cual incluye una secuencia
de sentencias entre las palabras claves LOOP y END LOOP. Veamos
un ejemplo
LOOP
secuencia_de_sentencias;
END LOOP;
En cada iteración del bucle, se ejecutan todas las sentencias de forma
secuencial. Evidentemente es raro que deseemos tener un bucle infinito
en un programa, por tanto existe una manera de forzar la salida, y es la
utilización de la palabra clave EXIT. Para esta palabra también tenemos
dos variedades posibles: EXIT y EXIT-WHEN. Vamos a verlas en
detalle.
2.3.1.1 EXIT
La sentencia EXIT provoca la salida de un bucle de forma
incondicional. Cuando se encuentra un EXIT, el bucle acaba
inmediatamente y el control pasa a la siguiente instrucción que esté fuera
del bucle. Veamos un ejemplo:
LOOP
…
IF limite_credito < 3 THEN
…
EXIT; -- Fuerza la salida inmediata…
END IF;
END LOOP;
-- El control pasaría a esta instrucción…
2.3.1.2 EXIT-WHEN
La sentencia EXIT-WHEN, nos va a permitir salir de un bucle de
forma condicional. Cuando PL/SQL encuentra una sentencia de este
tipo, la condición del WHEN será evaluada… en caso de devolver
TRUE, se provocará la salida del bucle… en caso contrario, se
continuará la iteración. Veamos un ejemplo:
LOOP
FETCH c1 INTO …
EXIT WHEN c1%NOTFOUND; -- Salir si se cumple la condición
…
END LOOP;
CLOSE c1;
De forma parecida a lo que ocurría con los IF y los ELSIF, también
podríamos controlar la salida de un bucle de otra forma, y no mediante
un EXIT-WHEN… lo que ocurre es que, al igual que en el caso anterior,
la utilización de esta sentencia facilitará la programación y lectura de
nuestro código. Veamos un ejemplo:
2.3.2 WHILE-LOOP
La sentencia WHILE-LOOP, asocia una condición a una secuencia de
instrucciones que se encuentran entre las palabras claves LOOP y END
LOOP. Veamos un ejemplo:
WHILE condicion LOOP
secuencia_de_instrucciones;
END LOOP;
Antes de cada iteración del LOOP, la condición se evalúa… si
devuelve TRUE se continúa iterando, en caso de que devuelva FALSE o
NULL, se forzará la salida del bucle.
El número de iteraciones depende de la condición, y es desconocido
hasta que el bucle termina. Puede haber 0 o N iteraciones hasta que la
condición sea FALSE.
Algunos lenguajes tienen estructuras como LOOP UNTIL, o
REPEAT UNTIL, las cuales evalúan la condición al final y no al
principio de todo. PL/SQL no tiene esta estructura, sin embargo sería
muy fácil simularla. Veamos un ejemplo:
LOOP
secuencia_de_instrucciones;
EXIT WHEN expresion_booleana;
END LOOP;
Para asegurarnos que un bucle de tipo WHILE se ejecuta por lo
menos una vez, podemos implementarlo mediante una variable booleana
de la siguiente forma:
hecho:=FALSE;
WHILE NOT hecho LOOP
secuencia_de_instrucciones;
hecho:=expresion_booleana;
END LOOP;
2.3.3 FOR-LOOP
Al contrario que en el caso de un bucle WHILE, en el cual recordemos
que el número de iteraciones era desconocido a priori, en un bucle FOR
este número es conocido antes de comenzar la iteración. Los bucles
FOR iteran un número de veces que está comprendido en un rango.
Veamos la sintaxis mediante un ejemplo:
FOR contador IN [REVERSE] valor_minimo..valor_maximo LOOP
secuencia_de_instrucciones;
END LOOP;
El rango es evaluado cuando se entra por primera vez en el bucle, y
nunca más se vuelve a evaluar.
Vemos unos cuantos ejemplos que pongan de manifiesto la utilización
del bucle FOR:
FOR i IN 1..3 LOOP -- Asigna los valores 1, 2, 3 a i
secuencia_de_instrucciones; -- Se ejecutan tres veces…
END LOOP;
FOR i IN 3..3 LOOP – Asigna el valor 3 a i
secuencia_de_instrucciones; -- Se ejecutan una vez…
END LOOP;
FOR i IN REVERSE 1..3 LOOP -- Asigna los valores 3, 2, 1 a i
secuencia_de_instrucciones; -- Se ejecutan tres veces…
END LOOP;
Dentro de un bucle FOR, el contador del bucle puede ser referenciado
como una constante… por lo tanto, el contador puede aparecer en
expresiones, pero no se le puede asignar ningún valor. Veamos un
ejemplo de esto:
FOR ctr IN 1..10 LOOP
IF NOT fin THEN
INSERT INTO … VALUES (ctr, …); -- Válido…
factor:=ctr*2; -- Válido…
ELSE
ctr:=10; -- No válido…
END IF;
END LOOP;
<<principal>>
DECLARE
ctr INTEGER;
BEGIN
…
FOR ctr IN 1..25 LOOP
…
IF principal.ctr>10 THEN … -- Referenciará a la variable global…
END LOOP;
END principal;
BEGIN
…
GOTO insercion_fila;
…
<<insercion_fila>>
INSERT INTO emp VALUES …
END;
En el ejemplo anterior, hemos visto un salto ‘hacia abajo’… veamos
ahora un salto ‘hacia arriba’:
BEGIN
…
<<actualizar_fila>>
BEGIN
UPDATE emp SET …
…
END;
…
GOTO actualizar_fila;
…
END;
<<fin_loop>> -- No válido…
END LOOP; -- Sentencia No ejecutable…
END;
Podríamos solucionarlo tan sólo incluyendo una sentencia ejecutable
después de la etiqueta, como por ejemplo NULL. Vamos a ver como lo
haríamos:
DECLARE
hecho BOOLEAN;
BEGIN
…
FOR i IN 1..50 LOOP
IF hecho THEN
GOTO fin_loop;
END IF;
…
<<fin_loop>>
NULL; -- Sentencia ejecutable…
END LOOP;
END;
2.4.1.1 Restricciones
Algunos destinos en un salto de tipo GOTO no están permitidos. De
forma específica, una sentencia GOTO no puede saltar a:
• Una sentencia IF
• Una sentencia LOOP
• Un Sub-Bloque
• Fuera de un Sub-Programa
Objetivos específicos
Que el alumno conozca como PL/SQL soporta las funciones de SQL,
permite SQL dinámico, y que además sepa definir y controlar cursores
sobre Bbdd.
Contenidos
Soporte SQL
Manejando Cursores
Empaquetando Cursores
Utilización de Cursores con bucles FOR
Cuaderno de notas
PL/SQL Básico
Unidad 6: Interacción con Oracle
3.1.4.2 LEVEL
Se utiliza LEVEL con la sentencia SELECT CONNECT BY, para
organizar los registros de una tabla de Bbdd en una estructura tipo árbol.
LEVEL devuelve el número de nivel de un nodo en una estructura tipo
árbol. El nivel raíz es 1, sus hijos son de nivel 2, sus nietos de nivel 3, y
así sucesivamente…
3.1.4.3 ROWID
ROWID devuelve el rowid (dirección binaria física) de una fila en una
tabla de la Bbdd. Recordemos que PL/SQL tiene un tipo de datos
llamado ROWID; se puede utilizar variables de este tipo, para almacenar
los rowids en un formato legible.
Cuando se selecciona una rowid dentro de un tipo ROWID, se debe
usar la función ROWIDTOCHAR, la cual convertirá el valor binario a
un string de caracteres de 18-bytes. Una vez hecho esto, podremos
comparar el valor de una variable ROWID con la pseudocolumna
ROWID en una claúsula WHERE de una sentencia UPDATE o
DELETE, para identificar el último registro recuperado en un cursor (Es
un ejemplo).
3.1.4.4 ROWNUM
ROWNUM devuelve el número lógico que nos indica el orden en el
cual una fila ha sido recuperada de una tabla por una sentencia SELECT.
DBMS_SQL.CLOSE_CURSOR(id_cursor);
EXCEPTION
/* Si se ejecuta la excepción, cerramos el cursor antes de salir */
WHEN OTHERS THEN
DBMS_SQL.CLOSE_CURSOR(id_cursor);
END drop table;
El SQL dinámico tiene mucha más potencia, y permite la ejecución de
sentencias que pueden ser simples, o incluso funciones y procedimientos
parametrizados. No es el objetivo del curso entrar en detalle sobre el
funcionamiento del SQL dinámico, puesto que es un tema bastante más
extenso y complicado. Una buena referencia sobre su funcionamiento lo
podemos encontrar en el libro Oracle 8 Application Developer's Guide.
DECLARE
CURSOR c1 IS
SELECT nom_emp, trab_emp
FROM emp
WHERE sal_emp<3000;
…
BEGIN
OPEN c1;
…
END;
Las filas del conjunto resultante no son recuperadas cuando se ejecuta
la sentencia OPEN, sino que lo serán más tarde cuando se ejecute la
sentencia FETCH.
END;
Para cambiar el resultado del conjunto, o los valores de las variables de
la consulta, se debe cerrar y abrir el cursor con las variables conteniendo
los nuevos valores.
Se puede utilizar un lista INTO diferente en fetches separados para el
mismo cursor. Veamos un ejemplo:
DECLARE
CURSOR c1 IS
SELECT nom_emp FROM emp;
nombre1 emp.nom_emp%TYPE;
nombre2 emp.nom_emp%TYPE;
nombre2 emp.nom_emp%TYPE;
BEGIN
OPEN c1;
FETCH c1 INTO nombre1; -- Recupera la primera fila…
FETCH c1 INTO nombre2; -- Recupera la segunda fila…
FETCH c1 INTO nombre3; -- Recupera la tercera fila…
…
CLOSE c1;
END;
Si se realiza un fetch después de haber recuperado la última fila de la
consulta, los valores de las variables son indeterminados.
DECLARE
bonus REAL;
BEGIN
FOR emp_rec IN (SELECT num_emp, sal_emp, com_emp FROM
emp) LOOP
bonus:=(emp_rec.sal_emp*0.05) + (emp_rec.com_emp*0.25);
INSERT INTO bonus_emp VALUES (emp_rec.num_emp, bonus);
END LOOP;
COMMIT;
END;
De todas formas, y aunque esto en ocasiones puede ser práctico para
evitarnos definir el cursor, se debe tener mucho cuidado al utilizarlo,
puesto que puede dificultar mucho la lectura del código fuente, e incluso
su mantenimiento posterior.
Objetivos específicos
Que el alumno conozca las excepciones predefinidas por PL/SQL, y
sepa a su vez, crear excepciones nuevas para el tratamiento de errores en
sus programas.
Contenidos
Introducción
Ventajas de la Excepciones
Excepciones Predefinidas
Excepciones definidas por el usuario
Cuaderno de notas
PL/SQL Básico
Unidad 7: Manejo de Errores
DECLARE
pe_ratio NUMBER(3,1);
BEGIN
SELECT precio/ganancias INTO pe_ratio FROM stocks
WHERE simbolo=’XYZ’; -- Esto puede causar el error de división
entre cero…
INSERT INTO estadis (simbolo,ratio) VALUES (‘XYZ’,pe_ratio);
COMMIT;
EXCEPTION
WHEN ZERO_DIVIDE THEN -- Controla la excepción…
INSERT INTO estadis (simbolo,ratio) VALUES (‘XYZ’,NULL);
COMMIT;
…
WHEN OTHERS THEN -- Controla el resto de excepciones…
ROLLBACK;
END; -- El manejador de errores y el bloque acaban aquí…
Este último ejemplo ilustra el manejo de errores, no la óptima
utilización del INSERT, puesto que nos podríamos haber ahorrado la
excepción simplemente escribiendo la sentencia de la siguiente forma:
INSERT INTO estadis (simbolo,ratio)
SELECT simbolo, DECODE(ganancias,0,NULL,precio/ganancias)
FROM stocks WHERE simbolo=’XYZ’;
SELECT …
-- Controlamos el error ‘no data found’…
El procesamiento de errores no está claramente diferenciado del
proceso normal… no es una programación robusta.
Veamos como deberían escribirse estas líneas de código…
BEGIN
SELECT …
SELECT …
SELECT …
…
EXCEPTION
WHEN NO_DATA_FOUND THEN -- Controla el error…
…
END;
Las excepciones mejoran la lectura del código, ya que las rutinas
principales no se ven mezcladas con las rutinas de manejo de errores.
Además el hecho de utilizar excepciones nos asegura que si se dispara
alguna excepción de ese tipo, nuestro programa en PL/SQL la tratará.
DUP_VAL_ON_INDEX ORA-00001 -1
INVALID_CURSOR Se intenta realizar una operación no válida sobre un cursor, como por
ejemplo cerrar un cursor que no ha sido abierto.
NOT_LOGGED_ON El programa PL/SQL realiza una llamada a Bbdd sin estar conectado
a Oracle.
ROWTYPE_MISMATCH La variable del cursor del host, y la variable del cursor de PL/SQL,
implicados en una sentencia de asignación, tienen tipos
incompatibles.
…
trata_salario(numero_empleado, incremento);
EXCEPTION
WHEN salario_nulo THEN
INSERT INTO auditoria_emp VALUES (numero_empleado,…);
COMMIT;
…
END;
Objetivos específicos
Que el alumno sepa definir Procedimientos y Funciones, así como
agruparlos posteriormente en Packages para mejorar la eficiencia y
modularidad del aplicativo.
Contenidos
Ventajas de los Subprogramas
Procedimientos y Funciones
Recursividad en PL/SQL
Concepto de Package
Ventajas de los Packages
Cuaderno de notas
PL/SQL Básico
Unidad 8: Subprogramas y Packages
5.2.1 Funciones
Una función es un subprograma que calcula un valor. Las funciones y
los procedimientos se estructuran igual, excepto que las funciones deben
tener una claúsula RETURN, es decir, deben devolver un valor. La
sintaxis general de una función es la siguiente:
FUNCTION nombre [ (parametro[, parametro, …])] RETURN
tipo_de_dato IS
[declaraciones_locales]
BEGIN
sentencias_ejecutables
[EXCEPTION
manejadores de excepciones]
END [nombre];
Donde parametro sigue la siguiente sintaxis:
nombre_parametro [IN | OUT | IN OUT] tipo_de_dato [{:= |
DEFAULT} expresion]
Al igual que en el caso de los procedimientos, no se le puede poner la
constraint de NOT NULL a un parámetro.
Especificación
Cuerpo
PACKAGE mi_package IS
-- Declaraciones públicas…
…
PROCEDURE proc1(…);
FUNCTION fun1(…) RETURN tipo_de_dato;
END mi_package;
5.5.1 Modularidad
Los packages permiten encapsular de manera lógica tipos, objetos y
subprogramas relacionados, en modulos PL/SQL con un mismo
nombre. Cada package es sencillo de entender, y los interfaces entre los
packages son simples, transparentes y bien definidos. Esto mejora el
desarrollo de la aplicación.
6 ANEXO 3:EJERCICIOS
END;
i, j INTEGER, INTEGER;
13.- Supongamos que tenemos un procedimiento llamado
calculo_integral, el cual está incluido en un package llamado
el_package_de_los_calculos, que su vez se encuentra en la instancia de
Bbdd llamada ORCL. ¿Como se haría para llamar a dicho procedimiento
en el caso de encontrarse conectado a la Bbdd ORCL con un usuario
que tuviera acceso al procedimiento?, ¿Y en el caso de no estar en
ORCL?
17.- ¿Qué valor contendrá la variable 'sumador' al salir del bucle?, ¿Por
qué?
DECLARE
sumador PLS_INTEGER;
BEGIN
FOR i IN 1..100 LOOP
sumador:=sumador+i;
END LOOP;
END;
cadena:='10*9*8*7*6*5*4*3*2*1'
No es necesario definirlo como un procedimiento o función, pero sí
declarar todas las variables necesarias para su correcto funcionamiento.
3.- ¿Qué tipo de binding para las variables utiliza PL/SQL?, ¿Qué
limitaciones tiene?, ¿Cómo las soluciona?.
4.- ¿Qué dos métodos generales tenemos para trabajar con Cursores en
PL/SQL?, ¿Cual es más cómodo?