lcg | uso de sentencias de control y ciclos

27
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

Upload: jesus-pereira

Post on 23-Mar-2016

221 views

Category:

Documents


0 download

DESCRIPTION

Ingenieria en sistemas de computacion

TRANSCRIPT

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('&gt; 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;