Post on 23-Mar-2016
description
Ingeniería en Sistemas de Computación
LENGUAJE DE CUARTA GENERACIÓN
Uso de sentencias de control y ciclos
Wilfrido Castilla | Profesor
Jesús Pereira | Alumno
I Generalidades
1. Objetivo de la práctica a. Detallar el uso de sentencias de control y de las
sentencias cíclicas existentes PLSQL, mediante la investigación bibliográfica y documental necesaria que permita su manipulación y comprensión completa.
b. Realizar la implementación de las sentencias descritas en métodos específicos de prueba y seguimiento, por medio del uso intensivo del
lenguaje, que les permita aprovechar lo aprendido en futuros proyectos o tareas.
2. Recomendaciones generales
a. Las sentencias de control en el lenguaje están
determinadas por el if-else,goto,loop,while,case y
for; en todos los casos su uso va a depender de la
necesidad específica del problema por resolver.
II Equipos y software Para realizar esta práctica el estudiante requiere: - El compilador de PLSQL.
- Entorno de desarrollo instalado y configurado (Instancia de Base de Datos).
III Procedimiento
1.1.1. Documentar y explicar las sentencias de control para Oracle.
1.1.2. Documentar y explicar las sentencias de manejo de errores.
1.1.3. Documentar y explicar la declaración de bloques en Oracle.
DECLARE
BEGIN
EXCEPTION
END;
1.1.4. Documentar y explicar la declaración de cursores en Oracle.
1.1.5. Documentar y explicar la declaración de procedimientos almacenados y funciones en Oracle.
1.1.6. Generar un ejercicio que utilice sentencias de control.
1.1.7. Generar un ejercicio que maneje la declaración de bloques.
1.1.8. Generar un cursor en la base de datos que ejecute alguna función.
1.1.9. Generar un procedimiento y una función.
1.1.10. El manejo de errores debe ser utilizado en los ejercicios anteriores.
Sentencias de control para Oracle Bifurcaciones condicionales – Bucles
Bifurcaciones condicionales:
IF La sintaxis básica es:
IF condición THEN
Bloque de instrucciones;
[ELSIF condición THEN
Bloque de instrucciones;]
...
[ELSE
Bloque de instrucciones;]
END IF;
Como en cualquier lenguaje de programación, “condición” es cualquier expresión que de
cómo resultado un valor booleano. Hay que saber que las estructuras IF se pueden
anidar unas dentro de otras.
IF – THEN
Se evalúa la condición y si resulta verdadera, se ejecutan uno o más líneas de código de
programa. En el caso de que la condición resulte falsa o nula, NO se realiza NINGUNA
acción.
IF fecha_nac < '1-01-1970' THEN --No termina con un ;
Salario := salario *1.15; --aumento de salario en un 15%
END IF;
Se pueden anidar varias instrucciones:
IF fecha_nac < ‘1-01-1970’ THEN
IF apellido =‘Martínez’ THEN
salario:= salario *1.15;
END IF;
END IF;
IF - THEN - ELSE
Se evalúa la condición y si resulta verdadera, se ejecutan uno o más líneas de código de
programa. En el caso de que la condición resulte falsa, se ejecutan las instrucciones que
siguen a la instrucción ELSE. Sólo se permite una instrucción ELSE en cada instrucción IF.
IF fecha_nac <’1-01-1970’ THEN
salario:= salario *1.15;
ELSE
salario:= salario* 1.05;
END IF;
IF - THEN - ELSIF
Se evalúa la condición y si resulta verdadera, se ejecutan uno o más líneas de código de
programa. En el caso de que la condición resulte ser falsa, se evalúa la condición
especificada en el ELSIF.
IF condicion THEN
instrucciones;
ELSE
IF condicion2 THEN
instrucciones;
ELSE
IF condicion3 THEN
instrucciones;
END IF;
END IF;
END IF;
IF apellido =„Pérez‟ THEN
salario:= salario *1.10; --aumento de salario en un 10%
ELSIF apellido =‘Martínez’ THEN
salario:= salario *1.15; --aumento de salario en un 15%
ELSIF apellido=‘Alvarez’ THEN
salario:= salario *1.20; --aumento de salario en un 20%
ELSE
salario:= salario* 1.05; --aumento de salario en un 5%
END IF; --Sólo se necesita un único END IF
CASE
La instrucción CASE puede evaluar múltiples expresiones y devolver para cada una de
ellas un valor/bloque de instrucciones. El resultado de cada WHEN puede ser un valor o
una sentencia, en el primer caso el resultado de una sentencia CASE se puede guardar en
una variable.
Su sintaxis:
CASE variable
WHEN expresión1 THEN valor1/bloque de instrucciones
WHEN expresión2 THEN valor2/bloque de instrucciones
WHEN expresión3 THEN valor3/bloque de instrucciones
WHEN expresión4 THEN valor4/bloque de instrucciones
ELSE valor5/bloque de instrucciones
END
Ejemplos:
CREATE TABLE C2(
Nombre VARCHAR2(20 ),
EC VARCHAR2(1)
);
COMMIT;
INSERT INTO C2 ( NOMBRE, EC ) VALUES ('Juan ', 'S');
INSERT INTO C2 ( NOMBRE, EC ) VALUES ('Maria', 'C');
INSERT INTO C2 ( NOMBRE, EC ) VALUES ('Ana', 'D');
INSERT INTO C2 ( NOMBRE, EC ) VALUES ('Luis', 'S');
INSERT INTO C2 ( NOMBRE, EC ) VALUES ('Pepe', NULL);
COMMIT;
SELECT Nombre, CASE EC
WHEN 'C' THEN 'Casado/a'
WHEN 'S' THEN 'Soltero/a'
WHEN 'D' THEN 'Divorciado/a'
ELSE 'Otros'
END
AS "Estado Civil"
FROM C2;
Otra sintaxis es:
CASE
WHEN condición1 THEN expresión1/bloque de instrucciones
WHEN condición2 THEN expresión2/bloque de instrucciones
WHEN condición3 THEN expresión3/bloque de instrucciones
WHEN condición4 THEN expresión4/bloque de instrucciones
ELSE expresión5/bloque de instrucciones
END
En esta sintaxis después del CASE no aparece ninguna variable y cada WHEN tiene su
propia condición a evaluar.
EJERCICIO Genere un script el cual muestre si un número está en el rango de las unidades, decenas o centenas. Utilizando la sentencia de control IF.
DECLARE
NUMERO NUMBER :=150;
BEGIN
IF NUMERO BETWEEN 1 AND 9 THEN
DBMS_OUTPUT.PUT_LINE('EL NUMERO PERTENECE A LAS UNIDADES');
ELSIF NUMERO BETWEEN 10 AND 99 THEN
DBMS_OUTPUT.PUT_LINE('EL NUMERO PERTENECE A LAS DECENAS');
ELSIF NUMERO BETWEEN 100 AND 999 THEN
DBMS_OUTPUT.PUT_LINE('EL NUMERO PERTENECE A LAS CENTENAS');
ELSE
DBMS_OUTPUT.PUT_LINE('EL NUMERO PERTENECE A OTRA UNIDAD');
END IF;
END;
Genere un script el cual muestre si un número es igual a algunos de los números dados en la lista.
Lista: 10 – 20 – 55 - 87 – 23
DECLARE
VAR NUMBER:=10;
BEGIN
IF VAR IN(10,20,55,87,23) THEN
DBMS_OUTPUT.PUT_LINE('PERTENECE A LOS NUMEROS DE LA LISTA');
ELSE
DBMS_OUTPUT.PUT_LINE('NO PERTENECE A LA LISTA');
END IF;
END;
Genere un script utilizando bifurcación case donde indiquemos que Smith es poco gentil, Ward es maravilloso, Blake es muy gentil, King es poco sensible y a los demás que no se indicaron colocar la palabra ‘ignorado’.
SELECT ENAME, EMPNO,
CASE
WHEN ENAME=UPPER('SMITH') THEN 'POCO GENTIL'
WHEN ENAME=UPPER('WARD') THEN 'MARAVILLOSO'
WHEN ENAME=UPPER('BLAKE') THEN 'MUY GENTIL'
WHEN ENAME=UPPER('KING') THEN 'POCO SENCIBLE'
ELSE 'IGNORADO'
END
FROM EMP;
Bucles:
LOOP
sentencias;
END LOOP;
Las sentencias de dentro del bucle se ejecutarán durante un número indefinido de
vueltas, hasta que aparezca la instrucción EXIT; que finalizará el bucle. Este tipo de bucle
se denomina bucle
incondicional.
LOOP
Sentencias
IF (expresion) THEN
Sentencias
EXIT;
END IF;
END LOOP;
Otra opción es incluir la estructura EXIT WHEN condición, se terminará el bucle cuando
la condición se cumpla:
LOOP
Sentencias
EXIT WHEN condición;
Sentencias
END LOOP;
Ejemplo:
DECLARE -- Declaración y asignación de variables
total NUMBER(9) := 0;
counter NUMBER(6) := 0;
BEGIN
LOOP
counter := counter + 1; -- Incrementamos la variable contador
total := total + counter * counter;
-- Salimos del bucle cuando la condición de cumpla
EXIT WHEN total > 25000;
END LOOP;
DBMS_OUTPUT.PUT_LINE('Counter: ' || TO_CHAR(counter) || ' Total: ' ||
TO_CHAR(total));
END;
Un tipo de bucle más común son los bucles condicionales:
WHILE condicion LOOP
Sentencias
END LOOP;
Ejemplo:
DECLARE
i NUMBER := 1;
i_cubed NUMBER;
BEGIN
WHILE i <= 10 LOOP
i_cubed := i**3;
DBMS_OUTPUT.PUT_LINE('Number: ' || TO_CHAR(i) || ' Cube: ' ||
TO_CHAR(i_cubed));
i := i + 1;
END LOOP;
END;
En los bucles WHILE también se pueden utilizar las órdenes EXIT o EXIT WHEN para
salirnos sin esperar a que la condición devuelva un valor falso.
Y por último el bucle FOR:
FOR contador IN [REVERSE] limite_inferior..limite_superior LOOP
sentencias
END LOOP;
Contador deberá ser una variable de tipo numérico que sea capaz de contener los
valores comprendidos entre limite_inferior y limite_superior, los cuales deberán ser
expresiones numéricas, ya sean constantes (1,10...) o funciones (ROUND(max,0),
ASCII(‘A’)...) .
Si la variable contador no está definida, PL/SQL definirá una variable de tipo INTEGER al
iniciar el bucle, y la liberará al finalizar el bucle.
SET SERVEROUTPUT ON;
BEGIN
FOR loop_counter IN 1..10 LOOP
DBMS_OUTPUT.PUT_LINE('Number: ' || TO_CHAR(loop_counter) || ' Square: ' ||
TO_CHAR(loop_counter**2));
END LOOP;
END;
En el caso de especificar REVERSE el bucle se recorre en sentido inverso.
LOOP = nosotros definimos cuando se va a salir del bucle.
EJERCICIO Genere un script el cual muestre las tablas de multiplicar según se indique. Tabla del 2.
DECLARE
TABLA NUMBER(2):=2;
RESULTADO NUMBER(2);
BEGIN
FOR i IN 1..10 LOOP
RESULTADO:=TABLA*i;
DBMS_OUTPUT.PUT_LINE (TO_CHAR(TABLA)|| ' X ' || TO_CHAR(i)|| ' = ' || TO_CHAR(RESULTADO));
END LOOP;
END;
Sentencias de manejo de errores y bloques para Oracle En PL/SQL tenemos mecanismos para manejar las excepciones, que son generadas a partir de situaciones de error o advertencias. Estos son administrados por bloques relativamente sencillos de utilizarlos, la sintaxis más común es la siguiente:
1 2 3 4 5 6 7
DECLARE -- Declaraciones objetos a utilizar BEGIN -- Ejecucion del proceso que desamos ejecutar EXCEPTION -- En caso de error, manejamos aqui la Excepcion END;
En caso que querríamos un manejo más fino en caso de errores, podemos especificar el
tipo de excepción y tratarlo de manera diferente según el caso, por ejemplo, si hay un
login fallido podemos tener un procedimiento distinto a si la excepción fue sobrecarga
de valor, al intentar asignar un valor más grande de lo que soporta el tipo. Sería asi:
1 2 3 4 5 6 7 8 9
10 11 12 13 14 15
DECLARE -- Declaraciones objetos a utilizar BEGIN -- Ejecucion del proceso que desamos ejecutar EXCEPTION WHEN LOGIN_DENIED THEN -- Se ejecuta cuando el programa intentó conectarse a Oracle con un nombre de usuario o password inválido WHEN VALUE_ERROR THEN -- Se ejecuta cuando ocurrió un error aritmético, de conversión o truncamiento. -- Por ejemplo, sucede cuando se intenta calzar un valor muy grande dentro de una variable más pequeña WHEN OTHERS THEN -- Se ejecuta cuando ocurre una excepcion de un tipo no tratado -- en los bloques anteriores END;
Como vemos en el caso anterior, la sentencia WHEN OTHERS THEN debe ir al final de la
lista de casos, si no colocamos esto una vez creada una lista de excepciones y nuestra
excepción no es de ningún tipo de los que verificamos, no habrá control del mismo.
Existe una lista bastante extensa de excepciones predefinidas, las cuales pueden verla en
la documentación oficial, listarla aquí sería algo largo.
También podemos capturar el número de error y el mensaje completo con 2 comandos
el SQLCODE y SQLERRM respectivamente, son muy utililes para comprender las
expciones que son controladas dentro del bloque OTHERS
1 2 3 4 5 6 7 8 9
10 11 12
DECLARE errno NUMBER; errmsg VARCHAR2(255); . . EXCEPTION WHEN OTHERS THEN errno := SQLCODE; errmsg := SQLERRM; -- ahora ya podemos utilizar estas variables para lo que querramos END;
Además de las predefinidas, el usuario puede crear sus propias excepciones,
personalizarlas según su necesidad por así decirlo. Con la sentencia RAISE podemos
lanzar la excepción en el momento que querramos, si se fijan en el siguiente ejemplo
verán que creamos un tipo de excepción personalizado y lo lanzamos manualmente para
luego ser controlado.
1 2 3 4 5 6 7 8 9
10 11 12 13
DECLARE -- Declaramos una excepcion llamada NO_NULL VALOR_NULL EXCEPTION; -- variable para comparar luego texto VARCHAR(15); BEGIN IF texto IS NULL THEN RAISE VALOR_NULL; END IF; EXCEPTION WHEN VALOR_NULL THEN dbms_output.put_line('> No se permiten valores nulos'); END;
Tambien podemos crear una excepción para que sea capturada por alguna aplicación y
no sea administrada completamente desde la base de datos.
1 2 3 4 5 6 7 8 9
10 11 12 13
DECLARE -- Declaramos una excepcion llamada NO_NULL VALOR_NULL EXCEPTION; -- variable para comparar luego texto VARCHAR(15); BEGIN IF texto IS NULL THEN RAISE VALOR_NULL; END IF; EXCEPTION WHEN VALOR_NULL THEN RAISE_APPLICATION_ERROR(-20001,'No se permiten valores nulos'); END;
Los bloques de PL/SQL pueden ser de los siguientes tipos:
Bloques anónimos
Subprogramas
Estructura de un Bloque
Los bloques PL/SQL presentan una estructura específica compuesta de tres partes bien diferenciadas:
La sección declarativa en donde se declaran todas las constantes y variables que se van a utilizar en la ejecución del bloque.
La sección de ejecución que incluye las instrucciones a ejecutar en el bloque PL/SQL.
La sección de excepciones en donde se definen los manejadores de errores que soportará el bloque PL/SQL.
Cada una de las partes anteriores se delimita por una palabra reservada, de modo que un bloque PL/SQL se puede representar como sigue:
[ declare | is | as ] /*Parte declarativa*/ begin /*Parte de ejecucion*/ [ exception ] /*Parte de excepciones*/ end;
De las anteriores partes, únicamente la sección de ejecución es obligatoria, que quedaría delimitada entre las cláusulas BEGIN y END. Veamos un ejemplo de bloque PL/SQL muy genérico. Se trata de un bloque anónimos, es decir no lo identifica ningún nombre. Los bloques anónimos identifican su parte declarativa con la palabra reservada DECLARE.
DECLARE /*Parte declarativa*/ nombre_variable DATE; BEGIN /*Parte de ejecucion * Este código asigna el valor de la columna "nombre_columna" * a la variable identificada por "nombre_variable" */ SELECT SYSDATE INTO nombre_variable FROM DUAL; EXCEPTION /*Parte de excepciones*/ WHEN OTHERS THEN dbms_output.put_line('Se ha producido un error'); END;
A continuación vamos a ver cada una de estas secciones
Sección de Declaración de Variables
En esta parte se declaran las variables que va a necesitar nuestro programa. Una variable se declara asignandole un nombre o "identificador" seguido del tipo de valor que puede contener. También se declaran cursores, de gran utilidad para la consulta de datos, y excepciones definidas por el usuario. También podemos especificar si se trata de una constante, si puede contener valor nulo y asignar un valor inicial.
La sintaxis generica para la declaracion de constantes y variables es:
nombre_variable [CONSTANT] <tipo_dato> [NOT NULL][:=valor_inicial]
donde:
tipo_dato: es el tipo de dato que va a poder almacenar la variable, este puede ser cualquiera de los tipos soportandos por ORACLE, es decir NUMBER , DATE , CHAR , VARCHAR, VARCHAR2, BOOLEAN ... Además para algunos tipos de datos (NUMBER y VARCHAR) podemos especificar la longitud.
La cláusula CONSTANT indica la definición de una constante cuyo valor no puede ser modificado. Se debe incluir la inicialización de la constante en su declaración.
La cláusula NOT NULL impide que a una variable se le asigne el valor nulo, y por tanto debe inicializarse a un valor diferente de NULL.
Las variables que no son inicializadas toman el valor inicial NULL.
La inicialización puede incluir cualquier expresión legal de PL/SQL, que lógicamente debe corresponder con el tipo del identificador definido.
Los tipos escalares incluyen los definidos en SQL más los tipos VARCHAR y BOOLEAN. Este último puede tomar los valores TRUE, FALSE y NULL, y se suele utilizar para almacenar el resultado de alguna operación lógica. VARCHAR es un sinónimo de CHAR.
También es posible definir el tipo de una variable o constante, dependiendo del tipo de otro identificador, mediante la utilización de las cláusulas %TYPE y %ROWTYPE. Mediante la primera opción se define una variable o constante escalar, y con la segunda se define una variable fila, donde identificador puede ser otra variable fila o una tabla. Habitualmente se utiliza %TYPEpara definir la variable del mismo tipo que tenga definido un campo en una tabla de la base de datos, mientras que%ROWTYPE se utiliza para declarar varibales utilizando cursores.
Ejemplos:
Estructura de un bloque anónimo.
DECLARE /* Se declara la variable de tipo VARCHAR2(15) identificada por v_location y se le asigna el valor "Granada"*/
v_location VARCHAR2(15) := ’Granada’;
/*Se declara la constante de tipo NUMBER identificada por PI y se le asigna el valor 3.1416*/ PI CONSTANT NUMBER := 3.1416;
/*Se declara la variable del mismo tipo que tenga el campo nombre de la tabla tabla_empleados identificada por v_nombre y no se le asigna ningún valor */ v_nombre tabla_empleados.nombre%TYPE;
/*Se declara la variable del tipo registro correspondiente a un supuesto cursor, llamado micursor, identificada por reg_datos*/ reg_datos micursor%ROWTYPE;
BEGIN /*Parte de ejecucion*/ EXCEPTION /*Parte de excepciones*/ END;
Estructura de un subprograma:
CREATE PROCEDURE simple_procedure IS /* Se declara la variable de tipo VARCHAR2(15) identificada por v_location y se le asigna el valor "Granada"*/
v_location VARCHAR2(15) := ’Granada’;
/*Se declara la constante de tipo NUMBER identificada por PI y se le asigna el valor 3.1416*/ PI CONSTANT NUMBER := 3.1416;
/*Se declara la variable del mismo tipo que tenga el campo nombre de la tabla tabla_empleados identificada por v_nombre y no se le asigna ningún valor */ v_nombre tabla_empleados.nombre%TYPE;
/*Se declara la variable del tipo registro correspondiente a un supuesto cursor, llamado micursor, identificada por reg_datos*/ reg_datos micursor%ROWTYPE;
BEGIN /*Parte de ejecucion*/ EXCEPTION /*Parte de excepciones*/ END;
EJERCICIO Genere un script el cual muestre el registro del empleado y su trabajo según el código dispuesto para este. Si no hay datos mostrar un error de no encontrado.
DECLARE
PERSONA EMP.ENAME%TYPE;
TRABAJO EMP.JOB%TYPE;
BEGIN
SELECT JOB
INTO TRABAJO
FROM EMP
WHERE EMPNO=7567;
DBMS_OUTPUT.PUT_LINE('REGISTRO ENCONTRADO: '||PERSONA||' TRABAJO ES '||TRABAJO);
EXCEPTION
WHEN no_data_found then
DBMS_OUTPUT.PUT_LINE('REGISTRO NO ENCONTRADO');
END;
Cursores en Oracle PL/SQL utiliza cursores para gestionar las instrucciones SELECT. Un cursor es un conjunto de registros devuelto por una instrucción SQL. Técnicamente los cursores son fragmentos de memoria que reservados para procesar los resultados de una consulta SELECT.
Podemos distinguir dos tipos de cursores:
Cursores implicitos. Este tipo de cursores se utiliza para operaciones SELECT INTO. Se usan cuando la consulta devuelve un único registro.
Cursores explicitos. Son los cursores que son declarados y controlados por el programador. Se utilizan cuando la consulta devuelve un conjunto de registros. Ocasionalmente también se utilizan en consultas que devuelven un único registro por razones de eficiencia. Son más rápidos.
Un cursor se define como cualquier otra variable de PL/SQL y debe nombrarse de acuerdo a los mismos convenios que cualquier otra variable. Los cursores implicitos no necesitan declaración.
El siguiente ejemplo declara un cursor explicito:
declare cursor c_paises is SELECT CO_PAIS, DESCRIPCION FROM PAISES; begin /* Sentencias del bloque ...*/ end;
Para procesar instrucciones SELECT que devuelvan más de una fila, son necesarios cursores explicitos combinados con un estructura de bloque.
Un cursor admite el uso de parámetros. Los parámetros deben declararse junto con el cursor.
El siguiente ejemplo muestra la declaracion de un cursor con un parámetro, identificado por p_continente.
declare
cursor c_paises (p_continente IN VARCHAR2) is SELECT CO_PAIS, DESCRIPCION FROM PAISES
WHERE CONTINENTE = p_continente; begin /* Sentencias del bloque ...*/ end;
El siguiente diagrama representa como se procesa una instrucción SQL a través de un cursor.
Cursores explícitos
Los cursores explícitos los utilizamos cuando tenemos consultas que nos devuelven más de una fila. Tenemos 4 operaciones básicas para trabajar con un cursor explícito.
1. Declaración del cursor: lo tenemos que declarar en la zona de declaraciones,
con el siguiente formato:CURSOR <nombrecursor> IS <sentencia SELECT>;
2. Apertura del cursor: Deberá colocarse en la zona de instrucciones, con el
siguiente formato:
OPEN <nombrecursor>;
Al hacerlo se ejecuta automáticamente la sentencia select y sus resultados se
almacenan en las estructuras internas de memoria manejadas por el cursor.
3. Recogida de información: Para recuperar la información anteriormente
guardada en las estructuras de memoria interna tenemos que usar el
siguiente formato:
FETCH <nombrecursor> INTO {<variable> | <listavariables>};
Si tenemos una única variable que recoge los datos de todas las columnas, el
formato de la variable seria el siguiente:
<variable> <nombrecursor>%ROWTYPE;
Si tenemos una lista de variables, cada una recogerá la columna
correspondiente de la cláusula select, por lo que serán del mismo tipo que las
columnas.
4. - Cierre del cursor:
CLOSE <nombrecursor>;
Ahora, veamos un ejemplo de utilización de cursores explícitos:
DECLARE
CURSOR C1 IS SELECT nombre, apellido FROM arbitro;
Vnom VARCHAR2(12);
Vape VARCHAR2(20);
BEGIN
OPEN C1;
LOOP
FETCH C1 INTO Vnom, Vape;
EXIT WHEN C1%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(Vnom || '' || Vapen);
END LOOP;
CLOSE C1;
END;
Si nos fijamos, en la declaración de los cursores explícitos no utilizamos la cláusula INTO,
que sí se utilizaba en los cursores implícitos.
Ademas podéis ver que después del FETCH hemos comprobado si nos devuelve valores
con la linea del EXIT. Es algo importante ya que si no nos devuelve nada el LOOP se
interrumpirá.
Atributos del cursor
Para conocer detalles de la situación del cursor tenemos 4 atributos:
%FOUND: devuelve verdadero di el ultimo FETCH ha recuperado algún valor;
en caso contrario devuelve falso; si el cursor no esta abierto nos devuelve
error.
%NOTFOUND: hace justamente lo contrario al anterior.
%ROWCOUNT: nos devuelve el número de filas recuperadas hasta el
momento.
%ISOPEN: devuelve verdadero si el cursor esta abierto.
Veamos ahora un ejemplo de utilización de %ROWCOUNT:
DECLARE
CURSOR C1 IS SELECT nombre from futbolista WHERE Cod='e1';
Vnom VARCHAR2(15);
BEGIN
OPEN C1;
LOOP
FETCH C1 INTO Vnom;
EXIT WHEN C1%NOTFOUND;
DBMS_OUTPUT.PUT_LINE (C1%ROWCOUNT || Vnom);
END LOOP;
CLOSE C1;
END;
Variables de acoplamientos en el manejo de cursores
En el ejemplo siguiente podemos observar que en la cláusula WHERE se incluye una variable que se debería haber declarado previamente. Este tipo de variables reciben el nombre de variables de acoplamiento. El programa la sustituirá por su valor en el momento en que se abre el cursor, y se seleccionarán las filas según dicho valor. Aunque ese valor cambie durante la recuperación de los datos con FETCH, el conjunto de filas que contiene el cursor no variará.
El ejemplo nos muestra los futbolistas de un equipo cualquiera.
CREATE OR REPLACE PROCEDURE ver_futbolistas_por_equipos(codeq VARCHAR2)
IS
Vequi VARCHAR2(3);
CURSOR C1 IS SELECT nombre from futbolista where codeq=Vequi;
Vnom VARCHAR(15);
BEGIN
vequi:=codeq;
OPEN C1;
FETCH C1 INTO vnom;
WHILE C1%FOUND LOOP
DBMS_OUTPUT.PUT_LINE(Vnom);
FETCH C1 INTO Vnom;
END LOOP;
CLOSE C1;
END;
Variables de acoplamiento
Si os fijáis en el siguiente ejemplo veréis que en la cláusula where se incluye una variable que se deberá declarar previamente. Este tipo de variables recibe el nombre de variables de acoplamiento. El programa la sustituirá por su valor en el momento en que se abre el cursor, y se seleccionarán las filas según dicho valor.
Create or replace procedure ver_jugador(codeq varchar2)
IS
vequi varchar2(3);
cursor c1 is select nombre from jugador where cod=vequi;
vnom varchar2(15);
BEGIN
vequi:=codeq;
OPEN c1;
FETCH c1 INTO vnom;
WHILE c1%found LOOP
DBMS_OUTPUT.PUT_LINE(vnom);
FETCH c1 INTO vnom;
END LOOP;
CLOSE c1;
END;
Cursor FOR …. LOOP
El trabajo normal de un cursor consiste en declarar un cursor, declarar una variable que recogerá los datos del cursor, abrir el cursor, recuperar con fetch, una a una, las filas extraídas introduciendo los datos en las variables, procesándolos y comprobando si se han recuperado datos o no.
Para resumir todas esas tareas, tenemos una estructura cursor FOR...LOOP que hace
todas estas cosas de forma implícita, todas menos la declaración del cursor.
El formato y el uso de esta estructura es:
1. se declara la información cursor en la sección correspondiente
2. Se presenta el cursor utilizando el siguiente formato: FOR nombreVarReg IN
nombreCursor
LOOP …. END LOOP;
Al entrar en el bucle se abre el cursor de manera automática, se declara
implícitamente la variable nombreVarReg de tipo nombrecursor%ROWTYPE y
se ejecuta el primer fetch cuyo resultado quedarán en nombreVarReg. A
continuación se realizaran las acciones que correspondas hasta llegar al END
LOOP.
DECLARE
cursor c2 is select nombre, peso, estatura from jugador where salario>1200;
BEGIN
FOR vreg IN c2 LOOP
DBMS_OUTPUT.PUT_LINE (vreg.nombre || '-' ||vreg.peso || '-' || vreg.estatura);
END LOOP;
END;
Cursores con parámetros
Un cursor puede tener parámetros; en este caso se aplicara el siguiente formato genérico:
CURSOR nombrecursor [(parámetros)] IS SELECT <sentencia select en la que
intervendrán los parámetros>;
Los parámetros formales indicados después del nombre del cursor tienen la siguiente
sintaxis:
nombreCursor [IN] tipodato [{:=|DEFAULT} valor]
Todos los parámetros formales de un cursor son parámetros de entrada y su ámbito es
local al cursor por eso sólo pueden ser referenciados dentro de la consulta.
Un ejemplo seria el siguiente:
DECLARE
...
CURSOR C1 (vpeso number, vestatura number DEFAULT 170) is select nficha, nombre
FROM emple WHERE estatura=vestatura AND peso=vpeso;
Para abrir un cursor con parámetros lo haremos de la siguiente forma:
OPEN nombrecursor [(parámetros)];
EJERCICIO Genere un script el cual muestre el id del empleado, su nombre y su comisión según el número de departamento. Utilizando cursores.
DECLARE
COD EMP.EMPNO%TYPE;
NOMBRE EMP.ENAME%TYPE;
COMICION EMP.COMM%TYPE;
VAR EMP.DEPTNO%TYPE:=20;
CURSOR C1 IS
SELECT EMPNO,ENAME,COMM
FROM EMP
WHERE DEPTNO=VAR;
BEGIN
OPEN C1;
LOOP
FETCH C1 INTO COD,NOMBRE,COMICION;
DBMS_OUTPUT.PUT_LINE('CODIGO: '||COD||' NOMBRE: '||NOMBRE||' CON UNA COMICION DE: '||COMICION);
EXIT WHEN C1%NOTFOUND;
END LOOP;
CLOSE C1;
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('DATO NO ENCONTRADO');
END;
Procedimientos almacenados y funciones en Oracle Oracle permite acceder y manipular información de la base de datos definiendo objetos procedurales (subprogramas) que se
almacenan en la base de datos. Estos objetos procedurales son unidades de programa PL/SQL:
Funciones y Procedimientos almacenados.
• Los procedimientos o funciones son bloques PL/SQL con nombre, que pueden recibir
parámetros y pueden ser invocados desde distintos entornos: SQL*PLUS, Oracle*Forms,
desde otros procedimientos y funciones y desde otras herramientas Oracle y
aplicaciones.
• Los procedimientos y funciones llevan a cabo tareas específicas, y su mayor diferencia
radica en que las funciones devuelven un valor.
Sintaxis Procedimientos
CREATE [OR REPLACE} PROCEDURE [esquema].nombre-procedimiento
(nombre-parámetro {IN | OUT | IN OUT} tipo de dato, ..) {IS | AS}
Declaración de variables;
Declaración de constantes;
Declaración de cursores;
BEGIN
Cuerpo del subprograma PL/SQL;
EXCEPTION
Bloque de excepciones PL/SQL;
END;
Sintaxis Funciones
CREATE [OR REPLACE] FUNCTION [esquema].nombre-función
(nombre-parámetro {IN | OUT | IN OUT} tipo-de-dato, ...)
RETURN tipo-de-dato {IS | AS}
Declaración de variables;
Declaración de constantes;
Declaración de cursores;
BEGIN
Cuerpo del subprograma PL/SQL;
EXCEPTION
Bloque de excepciones PL/SQL;
END;
Descripción de la sintaxis:
• Nombre-parámetro: es el nombre que queramos dar al
parámetro. Podemos utilizar múltiples parámetros. En caso de
no necesitarlos, podemos omitir los paréntesis.
• IN: especifica que el parámetro es de entrada y que por tanto
dicho parámetro tiene que tener un valor en el momento de
llamar a la función o procedimiento. Si no se especifica nada,
los parámetros son por defecto de tipo entrada.
• OUT: especifica que se trata de un parámetro de salida. Son
parámetros cuyo valor es devuelto después de la ejecución el
procedimiento al bloque PL/SQL que lo llamó. Las funciones
PLSQL no admiten parámetros de salida.
• IN OUT: Son parámetros de entrada y salida a la vez.
• Tipo-de-dato: Indica el tipo de dato PLSQL que corresponde al
parámetro (NUMBER, VARCHAR2, etc).
Ejemplo de creación de un procedimiento
CREATE OR REPLACE PROCEDURE contratar_empleado
(w_codigo_emp IN emp.codigo_emp%TYPE,
w_depart IN emp.cod_depart%TYPE,
w_fecha_alta IN emp.fecha_alta%TYPE)
IS
BEGIN
INSERT INTO emp(código_emp, fecha_alta, cod_depart)
VALUES (w_código_emp, w_fecha_alta, w_depart);
END contratar_empleado;
En este procedimiento se ha definido el tipo de dato de los parámetros de
entrada como del mismo tipo que los campos de la tabla “emp” , es decir:
nombreParametro IN nombreTabla.nombreColumna%TYPE.
Sería equivalente a poner:
w_codigo_emp number,
w_depart varchar..
• Cuando se crea un procedimiento o función, Oracle automáticamente compila el
código fuente, guarda el código objeto en un área compartida de la SGA (System Global
Area) y almacena tanto el código fuente como el código objeto en catálogos del
diccionario de datos.
• El código objeto permanece en la SGA, por tanto, los procedimientos o funciones se
ejecutan más rápidamente y lo pueden compartir muchos usuarios. Cuando es necesario
liberar áreas de la SGA, Oracle aplica el algoritmo ‘menos-usado-recientemente’. Si en
un momento determinado se libera el área SQL de un procedimiento o función, la
próxima vez que se ejecute se vuelve a cargar el código objeto, que está almacenado en
catálogo, en la SGA
EJERCICIO Genere un script el cual muestre la sumatoria de dos números. En base a una función y luego a un procedimiento almacenado.
Función
CREATE OR REPLACE
FUNCTION SUMATORIA(N1 INT, N2 INT)
RETURN INT
AS
RESULTADO INT;
BEGIN
RESULTADO:=N1+N2;
RETURN RESULTADO;
END;
DECLARE
N1 NUMBER;
N2 NUMBER;
VAR NUMBER;
BEGIN
N1:=NULL;
N2:=NULL;
VAR:=SUMATORIA(8,10);
DBMS_OUTPUT.PUT_LINE('EL RESULTADO ES: '||VAR);
END;
Procedimiento
CREATE OR REPLACE
PROCEDURE SUMA(N1 INT, N2 INT, RESULTADO OUT INT)
AS
BEGIN
RESULTADO:=N1+N2;
END;
DECLARE
RESULTADO NUMBER;
BEGIN
SUMA(3,2,
RESULTADO=>RESULTADO);
DBMS_OUTPUT.PUT_LINE('EL RESULTADO ES: '||RESULTADO);
END;