Tema 18 Cursores

24
Tema 18 Cursores, excepciones y control de transacciones en PL/SQL Tema 18 Cursores, excepciones y control de transacciones en PL/SQL 1. Cursores 2. Cursores explícitos 3. Atributos del Cursor 4. Variables de acoplamiento en el manejo de cursores 5. Cursor For..Loop 6. uso de alias en las columnas de selección del cursor 7. Cursores con parámetros 8. Atributos en cursores implícitos 9. Excepciones 10. Excepciones internas 11. Excepciones definidas por el usuario 12. Otras Excepciones 13. Propagación y ámbito de las Excepciones 14. Utilización de Raise_Application_Error 15. Control de Transacciones 16. Uso de cursores para actualizar filas 17. Ejercicios 1.- Cursores: Hasta el momento hemos venido usando cursores implícitos. Este tipo es muy sencillo, pero plantea un problema: La subconsulta devuelve una fila, y sólo una, de lo contrario se produciría un error, por ello, dado que normalmente una consulta devolverá varias filas, se suelen manejar cursores explícitos. 2.-Cursores explícitos Se utilizan para trabajar con subconsultas que pueden devolver mas de una fila. Hay 4 operaciones básicas para trabajar con cursores explícitos: 1. Declaración del cursor: Se declara en la zona de declaración, según la siguiente sintaxis: CURSOR <nombre_cursor> IS SELECT <sentencia_sql>; Prácticas de diseño y gestión de bases de datos 1

Transcript of Tema 18 Cursores

Page 1: Tema 18 Cursores

Tema 18 Cursores, excepciones y control de transacciones en PL/SQL

Tema 18 Cursores, excepciones y control de transacciones en PL/SQL

1. Cursores 2. Cursores explícitos 3. Atributos del Cursor 4. Variables de acoplamiento en el manejo de cursores 5. Cursor For..Loop 6. uso de alias en las columnas de selección del cursor 7. Cursores con parámetros 8. Atributos en cursores implícitos 9. Excepciones 10. Excepciones internas 11. Excepciones definidas por el usuario 12. Otras Excepciones 13. Propagación y ámbito de las Excepciones 14. Utilización de Raise_Application_Error 15. Control de Transacciones 16. Uso de cursores para actualizar filas 17. Ejercicios

1.- Cursores:

Hasta el momento hemos venido usando cursores implícitos. Este tipo es muy sencillo, pero plantea un problema:

La subconsulta devuelve una fila, y sólo una, de lo contrario se produciría un error, por ello, dado que normalmente una consulta devolverá varias filas, se suelen manejar cursores explícitos.

2.-Cursores explícitos

Se utilizan para trabajar con subconsultas que pueden devolver mas de una fila. Hay 4 operaciones básicas para trabajar con cursores explícitos:

1. Declaración del cursor: Se declara en la zona de declaración, según la siguiente sintaxis:CURSOR <nombre_cursor> IS SELECT <sentencia_sql>;

2. Apertura del cursor: En la zona de instrucciones(Begin) habrá que abrir el cursor.OPEN <Nombre_cursor>;

Al hacerlo se ejecuta automáticamente la sentencia select asociada y sus resultados se almacenan en las estructuras internas de memoria, manejadas por el cursor.

3. Recogida de información: Para recoger la información almacenada en el cursor usaremos la siguiente sintaxis:

Prácticas de diseño y gestión de bases de datos 1

Page 2: Tema 18 Cursores

Tema 18 Cursores, excepciones y control de transacciones en PL/SQL

FETCH <Nombre_cursor> INTO {<variable>|<lista_variable>};

Después del into figurará una variable que recogerá la información relativa a todas las columnas de una fila.

En este caso la variable puede ser declarada de esta manera en la zona de declaración:

<variable> <nombre_cursor>%rowtype;

Cada una recogerá la columna correspondiente a la cláusula select, por tanto serán del mismo tipo que las columnas. Cada fetch lo que hace es recuperar una fila y el cursor avanza automáticamente a la fila siguiente.

4. Cierre del Cursor:

Cuando el cursor no se va a utilizar, hay que cerrarlo:

CLOSE <nombre_cursor>;

Ejemplo: Vamos a visualizar el nombre y apellidos de todos los clientes.

/*-----declaracion*/declare

cursor nom_apell is select clt_nom,clt_apell fromclientes;

nombre clientes.clt_nom%type;

apellido clientes.clt_apell%type;

begin/*apertura*/

open nom_apell;

/*recogida de datos*/

fetch nom_apell into nombre,apellido;

while nom_apell%found loop

Prácticas de diseño y gestión de bases de datos

Clt_num Clt_nomPepe Borrás

2

Page 3: Tema 18 Cursores

Tema 18 Cursores, excepciones y control de transacciones en PL/SQL

dbms_output.put_line('El nombre es: '||nombre ||' Elapellido es: '||apellido);

fetch nom_apell into nombre, apellido;

exit when nom_apell%notfound;

end loop;

/*cierre de cursor*/

close nom_apell;

end;/

A diferencia de lo que ocurre con los cursores implícitos, la cláusula into, no aparece con la select, sino que aparece con Fetch. Cada vez que accede a una fila se guarda.

Explícitos: Con el fetch, Para visualizar un conjunto de filas.

Implícitos: Siempre una filaSelect into variableVariable clientes.clt_nim%type;

3.- Atributos del Cursor:

Para conocer los detalles respecto a la situación del cursor, hay 4 atributos para consultar.

1.- %Found : Devuelve verdadero si el último fetch ha recuperado algún valor, en caso contrario devuelve falso. Si el cursor no está abierto, devolverá error y si estaba abierto, pero no se había ejecutado aún ningún fetch, devuelve null. Se puede utilizar como condición de continuación en bucles para recuperar información.

Fetch nom_apell into nombre, apellido;

while nom_apell%found loopdbms_output.put_line('El nombre es: '||nombre ||' Elapellido es: '||apellido);fetch nom_apell into nombre,apellido;exit when nom_apell%notfound;

end loop;

2.- %NotFound

Se suele utilizar como una condición de salida de un bucle.

Prácticas de diseño y gestión de bases de datos 3

Page 4: Tema 18 Cursores

Tema 18 Cursores, excepciones y control de transacciones en PL/SQL

EXIT WHEN CUR1 %NOTFOUND;

3.- %ROWCOUNT

Devuelve él numero de filas recuperadas hasta el momento. Es un número.

4.-%ISOPEN:

Devuelve verdadero si el cursor está abierto.

4.-Variables de acoplamiento en el manejo de cursores

En una select para introducir una condicion, usamos un where. En Pl/Sql se suele utilizar un diseño mas abierto porque los términos exactos de esa condición, se conocen en tiempo de ejecución. Deseamos consultar los clientes k viven en una determinada ciudad.

Proc viven_en()create or replace procedure viven_en(ciudad clientes.clt_pob%type)is

cursor nom_apell is select clt_nom,clt_apell from clienteswhere clt_pob =ciudad;

nombre clientes.clt_nom%type;apellido clientes.clt_apell%type;begin/*apertura*/

open nom_apell;/*recogida de datos*/

fetch nom_apell into nombre,apellido;

while nom_apell%found loopdbms_output.put_line('El nombre es: '||nombre ||' El apellido es:

'||apellido);fetch nom_apell into nombre,apellido;exit when nom_apell%notfound;

end loop;/*cierre de cursor*/close nom_apell;end;/

SQL> @viven_en

Procedure created.

SQL> exec viven_en('MADRID')El nombre es: Miguel El apellido es: PEREZEl nombre es: Diego El apellido es: CORTESEl nombre es: Joaquin El apellido es: FERNANDEZ

Prácticas de diseño y gestión de bases de datos 4

Page 5: Tema 18 Cursores

Tema 18 Cursores, excepciones y control de transacciones en PL/SQL

PL/SQL procedure successfully completed.

AHORA con rowtype

create or replace procedure viven_en(ciudad clientes.clt_pob%type)is

cursor nom_apell is select * from clienteswhere clt_pob =ciudad;

nombre clientes%rowtype;begin/*apertura*/

open nom_apell;/*recogida de datos*/

DBMS_OUTPUT.PUT_LINE('<<--------Relacion de clientes de: '||ciudad||'------------>>');

DBMS_OUTPUT.PUT_LINE(' ');fetch nom_apell into nombre;while nom_apell%found loop

dbms_output.put_line('El nombre es: '||nombre.clt_nom);fetch nom_apell into nombre;exit when nom_apell%notfound;

end loop;/*cierre de cursor*/close nom_apell;end;/

SQL> exec viven_en('PARIS');<<--------Relacion de clientes de: PARIS------------>>El nombre es: JeanEl nombre es: Marcel

PL/SQL procedure successfully completed.

5.- Cursor For..Loop

Hasta ahora hemos visto que el trabajo del cursor consiste en lo siguiente:1.-Declarar el cursor.2.-Declarar una variable que recoge los datos del cursor3.-Abrir el cursor4.-Recuperar con fech luna a una las filas extraídas, introduciendo los datos en La/s variable/s.

Pl/SQl proporciona la estructura de cursor Cursor for..loop que simplifica estas tareas, realizando todas ellas, excepto la declaración del cursor.

Prácticas de diseño y gestión de bases de datos 5

Page 6: Tema 18 Cursores

Tema 18 Cursores, excepciones y control de transacciones en PL/SQL

For <nombre_variable> in <nombre_cursor> loop

End loop;

Ejemplo: Recoger todos los clientes españoles

create or replace procedure viven(pais clientes.clt_pais%type)is

cursor cur is select * from clientes where clt_pais=pais;

begindbms_output.put_line('--------Clientes de : '||pais||'---------------');for variable in cur loop

dbms_output.put_line('El nombre es: '||variable.clt_nom);end loop;end;/

SQL> @viven

Procedure created.

SQL> exec viven('E');--------Clientes de : E---------------El nombre es: MargaritaEl nombre es: MiguelEl nombre es: AntoniEl nombre es: PabloEl nombre es: ConsueloEl nombre es: PauEl nombre es: JorgeEl nombre es: PabloEl nombre es: DiegoEl nombre es: JoaquinEl nombre es: JacintoEl nombre es: Pedro

PL/SQL procedure successfully completed.Cómo vemos no tenemos que hacer nada de fetch!!!!!!

La variable se declara implícitamente, por tanto es local al procedure. Al salir del bucle, la variable no estará disponible.

6.-Uso de alias en las columnas de selección del cursor.

Cuando las columnas son expresiones, usaremos alias. Por ejemplo: Cuánto ha vendido cada tienda??

Prácticas de diseño y gestión de bases de datos 6

Page 7: Tema 18 Cursores

Tema 18 Cursores, excepciones y control de transacciones en PL/SQL

declarecursor alias is select vnt_tda as

tienda,sum(vnt_cant*vnt_precio) as total from ventasgroup by vnt_tda;

begindbms_output.put_line( '*************** Relacion de Tiendas

*************');for fila in alias loop

dbms_output.put_line('Código de la tienda : '|| fila.tienda||' Total: '||fila.total);

end loop;end;/

SQL> @alias*************** Relacion de Tiendas *************Código de la tienda : 1 Total: 3580Código de la tienda : 2 Total: 20200Código de la tienda : 3 Total: 10700Código de la tienda : 4 Total: 5380Código de la tienda : 5 Total: 18000Código de la tienda : 6 Total: 7200Código de la tienda : 7 Total: 5580Código de la tienda : 8 Total: 600Código de la tienda : 9 Total: 500Código de la tienda : 10 Total: 600Código de la tienda : 11 Total: 44380Código de la tienda : 12 Total: 2800

PL/SQL procedure successfully completed.

Input truncated to 1 characters

7.-Cursores con parámetros:

Un cursor puede tener parámetros, en éste caso usaremos la siguiente sintaxis.

CURSOR nombre_cursor[(parámetro1,parámetro2,....)]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.

Nombre_variable[in] tipo_dato[{:=|default}valor ]

Todos los parámetros de un cursor son parámetros de entrada. El ámbito de estos parámetros es local al cursor, por eso solamente pueden ser referenciados dentro de la consulta.Ejercicio que utilizamos un cursor y un parámetro(clt_num).Lo abriremos con open cur

Prácticas de diseño y gestión de bases de datos 7

Page 8: Tema 18 Cursores

Tema 18 Cursores, excepciones y control de transacciones en PL/SQL

create or replace procedure ver_cliente(codigo clientes.clt_num%type)is

CURSOR parametro (codigo clientes.clt_num%type) is select clt_apell from clientes where clt_num=codigo;

nombre clientes.clt_apell%type;beginopen parametro (codigo);

fetch parametro into nombre;dbms_output.put_line('El apellido es : '||nombre);

close parametro;end;/

declaramos el cursor con el parámetro k recibirá.Al abrirlo le pasamos código, con lo k se posiciona en el registro”codigo”. Una vez echo esto con el fetch recogemos en una variable el contenido cursor(codigo), para mostrar este dato usaremos dbms_out.put_line

SQL> @parametroInput truncated to 1 characters

Procedure created.

SQL> exec ver_cliente(3);El apellido es : DUPONT

PL/SQL procedure successfully completed.Otro:

create or replace procedure pais(pais clientes.clt_pais%type)is

cursor parametro (pais clientes.clt_pais%type) is select clt_nom,clt_apell from clientes

where clt_pais=pais;nombre clientes.clt_nom%type;apellido clientes.clt_apell%type;begin

open parametro(pais);fetch parametro into nombre,apellido;dbms_output.put_line('*/*/*/*/*/*/*/*/*Relacion de Clientes de : '

||pais||'/*/**/*/*/*/*/*/*/*/*/*/*/');while parametro%found loop

dbms_output.put_line(' El nombre es: '||nombre||' y su apellido es: ' ||apellido);

fetch parametro into nombre,apellido;exit when parametro%notfound;

end loop;

end;/

Prácticas de diseño y gestión de bases de datos 8

Page 9: Tema 18 Cursores

Tema 18 Cursores, excepciones y control de transacciones en PL/SQL

SQL> @parametro2Input truncated to 1 characters

Procedure created.

SQL> exec pais('F');*/*/*/*/*/*/*/*/*Relacion de Clientes de : F/*/**/*/*/*/*/*/*/*/*/*/*/El nombre es: Jean y su apellido es: DUPONTEl nombre es: Michel y su apellido es: DUPRETEl nombre es: Marcel y su apellido es: SOURISEl nombre es: Gerard y su apellido es: COURBON

PL/SQL procedure successfully completed.

8.- Atributos en cursores implícitos

Oracle abre implícitamente un cursor cuando proceso un comando sql, k no este asociado a un cursor implícito. El curso implícito dispone también de los cuatro atributos mencionados, que pueden facilitarnos información sobre la ejecución de los comandos select into,insert, update y delete.

SQL%NOTFOUND: Dará true si el último insert, update, delete ó select into ,han fallado. SQL%FOUND Devuelve true si el ultimo select, update o select into han afectado a mas filas.SQL%ROWCOUNT-> Devuelve el numero de filas afectadas por el ultimo insert...SQL%ISOPEN> Siempre devolverá falso, ya que oracle cierra automáticamente después de cada orden SQL.

Notas:a) el comportamiento de los articulos en los cursores

implícitos, es diferentes al de los cursores explicitos. En los implícitos, el cursor se cierra tras cerrar la orden select into.

b) devolverá un valor relativo a la ultima orden select,update o select into.

c) En el caso de select into debemos tener en cuenta que ha de devolver una fila y solo una, pues de lo contrario se producirá un error y se producirá una excepción

a. No_data_found: Si la consulta no devuelve ninguna fila

b. Too_many_rows: Si la consulta devuelve mas de una.

d) Lo indicado anteriormente, no es aplicable a insert, update y delete.

Prácticas de diseño y gestión de bases de datos 9

Page 10: Tema 18 Cursores

Tema 18 Cursores, excepciones y control de transacciones en PL/SQL

Con la tabla clientes, Bloque que ponga todas las poblaciones a Sevilla

Select cuya población sea Málaga, que muestre el error.(ya k no existe ninguna con Málaga)

declare ciudad varchar2(15);beginciudad:='Malaga';

update clientesset clt_pob=ciudad where clt_pob like'%SEVILLA';if (sql%notfound) then

dbms_output.put_line('No se encontró niguna ciudad!!');

end if;end;

SQL> @malagaNo se encontró niguna ciudad!!

PL/SQL procedure successfully completed.

Input truncated to 1 characters

Ahora probamos con un select y vemos si pasa primero por exception o por el sql%notfound:

declare ciudad varchar2(15);begin

select clt_pob into ciudad from clienteswhere clt_pob like'%SEVILLA';

if (sql%notfound) thendbms_output.put_line('No se encontró niguna ciudad!!

por el sql%found');end if;

exception

when no_data_found thendbms_output.put_line('No se encontró niguna ciudad!!

por la excepcion');

end;/

SQL> @malaga1Input truncated to 1 charactersNo se encontró niguna ciudad!! por la excepcion

PL/SQL procedure successfully completed.

Prácticas de diseño y gestión de bases de datos 10

Page 11: Tema 18 Cursores

Tema 18 Cursores, excepciones y control de transacciones en PL/SQL

Como vemos ha saltado primero por la excepción. Siempre que tratemos un cursor implícito y sea un select into, hemos de controlar sus errores mediante las excepciones y no mediante los atributos del cursor. Si realizamos una selección y después un update

Cuando un select into hace referencia a una función de grupo, nunca se levantará la excepción no_data_found, y Sql%found siempre será verdadero. Ello es debido a que las funciones de grupo, siempre devuelven un valor, aunque sea null. Al hacer un select into si devuelve null no entrara en la excepción no_data_found, ya que realmente es un dato.

9. Excepciones

Las excepciones sirven para tratar errores en tiempo de ejecución, así como errores y situaciones definidas por el usuario. Cuando se produce un error, PL/SQL levanta una excepción y pasa el control de éste a la sección excepción, que actuará según lo establecido y dará por finalizado el bloque actual.

EXCEPTIONWHEN <nombre_excepcio1> then

<instrucciones>;WHEN <nombere_excepcion2> then

………[WHEN OTHERS

<instrucciones>;]

Tipos de excepciones:1.- Excepciones internas2.- Definidas por el usuario3.- Otras excepciones

10.- Excepciones internas predefinidas.

Estas excepciones están predefinidas en oracle. Se disparan automáticamente al producirse determinados errores.

SQL> SELECT 2/0 FROM DUAL;SELECT 2/0 FROM DUAL *ERROR at line 1:ORA-01476: divisor is equal to zero

1.- Excepciones internas:Estas excepciones internas de Oracle y no hay que declararlas

en la sección declare.

2.- Definidas por el usuarioPasos:

Prácticas de diseño y gestión de bases de datos 11

Page 12: Tema 18 Cursores

Tema 18 Cursores, excepciones y control de transacciones en PL/SQL

1.-Se deben declarar en la sección declare de la siguiente forma:1)<Nombre de la excepción> EXCEPTION2)Se disparan en la sección ejecutable del programa mediante

al orden raise<nombre_excepcion>3)Se tratan en la sección excepción así:EXCEPTION

WHEN <name_exception> then<tratamiento>;

Seleccionar el precio de venta del articulos numero1. Abriremos el cursor Si el art_pv >100 then salta la excepción mayor_igual ymenor_igual_100;

declareCURSOR parametro is select art_pv from articulos where

art_num=1;

precio2 articulos.art_pv%type;menor_igual_100 exception;mayor_igual_100 exception;

beginopen parametro ;

fetch parametro into precio2;close parametro;if precio2<100 then

raise menor_igual_100;else

raise mayor_igual_100;end if;

exceptionwhen menor_igual_100 then

dbms_output.put_line('Error Ora<100');when mayor_igual_100 then

dbms_output.put_line('Error Ora>100');end;/

SQL> @exceptError Ora>100

PL/SQL procedure successfully completed.

11.-Otras Excepciones.

Existen otros tipos de errores, internos de oracle, similares a los asociados a las excepciones internas, pero no tienen asignada ninguna excepción, sino un codigo de error y un mensaje de error, que se accede mediante las funciones sqlcode y sqlerrm. Cuando se producen uno de estos errores, se pasa el controla la sección excepción, donde se tratara el error con la cláusula then others. También podemos asociar una excepción a algunos de los errores internos que no tienen excepciones predefinidas asociadas:

Prácticas de diseño y gestión de bases de datos 12

Page 13: Tema 18 Cursores

Tema 18 Cursores, excepciones y control de transacciones en PL/SQL

1. Definimos una excepción en la sección declare como si fuera una excepción definida por el user.

<nombre_excep> EXCEPTION;2. Asociamos esa excepción a un determinado código de error

mediante la directiva del compilador. PRAGMA EXCEPTION_INIT(nombre_exc,numero_error_en oracle)(esto va en declare).

13.- Propagación y ámbito de las excepciones:

La gestión de excepciones en pl/sql tiene unas reglas que se deben considerar en el diseño de aplicaciones.a) Cuando se levanta una excepción, el programa bifurca a la sección

excepción del bloque actual. Si no está definida en ella la excepción se propaga al bloque que llamó al bloque actual pasando el control a la sección excepción de dicho bloque y así sucesivamente hacia arriba-

b) Una vez tratada la excepción en un bloque, se devuelve la excepción al bloque que llamo al que trató la excepción.

c) Si después de tratar una excepción queremos volver a la línea siguiente a la que se produjo, no podemos hacerlo directamente.

d) La cláusula then others, tratará cualquier excepción que no aparezca en las cláusulas when correspondientes, con independencia del tipo de excepciones. De este modo se evitara que la cláusula se propague a los bloque s de nivel superior.

14.- Utilización de Raise_Application_Error

En el paquete dbms estándar se incluye un procedimiento muy util llamado raise_application_error. Que sirve para levantar errores y definir y enviar mensajes de errors. Su formato es:

RAISE_APPLICATION_ERROR(num_error,mensaje de error).Num_error es un numero comprendido entre –20.000 y –20.999.Mensaje de error es una cadena de 512 bytes. Cuando un programa hace esta llamada, se levanta la excepción y

deshacen los cambios realizados por ese programa.Insert into articulos values(20,null,null,null, null, null, null);

Crear un procedimiento que se llame subir precio, que se le pasará como parámetro el art_num y el incremento. Si hubiera algún error, pondremos el art_pv a null.

create or replace procedure subida(articulo articulos.art_num%type,incremento number)

isprecio articulos.art_pv%type;

beginselect art_pv into precio from articuloswhere art_num=articulo;if precio is null then

raise_application_error(-20900,'Error interno pepe oracle!!');

Prácticas de diseño y gestión de bases de datos 13

Page 14: Tema 18 Cursores

Tema 18 Cursores, excepciones y control de transacciones en PL/SQL

elseupdate articulosset art_pv=precio+incrementowhere art_num=articulo;

end if;end;/

SQL> Insert into articulos values(20,nu

1 row created.

SQL> commit;

Commit complete.

SQL> exec subida(20,100);BEGIN subida(20,100); END;

*ERROR at line 1:ORA-20900: Error interno pepe oracle!!ORA-06512: at "CHILI.SUBIDA", line 14ORA-06512: at line 1

15.-Control de Transacciones

Una transacción se puede definir como un conjunto de operaciones que se realizan en la BD. En una transacción es el usuario quien decide cuales serán las operaciones que compondrán la transacción. Oracle garantiza la consistencia de datos en una transacción en términos de vale o no vale nada, es decir, o se ejecutan todas las operaciones que componen la transacción o no se ejecuta ninguna, así pues, la BD tiene un estado antes de la transacción y un estado después de ésta, pero no hay estados intermedios. Una transacción en PL/SQL comienza con la primera orden SQL de la sesión de usuario o con la primera orden posterior a la finalización de la transacción anterior. La transacción finaliza cuando se ejecuta un comando de control de transacciones, como puede ser el commit o el rollback, una orden DDL o cuando finaliza la sesión.Comandos PL/SQL:

COMMIT WORK;EN LAS EXCEPCIONES:

WHEN OTHERS THEN ROLLBACK work;

Commit: da por concluida la transacción actual y hace definitivos los cambios efectuados, liberando las filas bloqueadas. Solo después de que se ejecute un commit, los usuarios tendrán acceso a los datos actualizados. RollBack : Da por concluida la transacción actual y deshace los cambios que se hubiesen producido. Se utiliza especialmente cuando

Prácticas de diseño y gestión de bases de datos 14

Page 15: Tema 18 Cursores

Tema 18 Cursores, excepciones y control de transacciones en PL/SQL

no se puede termina una transacción por que se levanta una excepción.SAVEPOINT: Se usa para poner marcas o puntos de salvaguarda al procesar transacciones se usa en conjunción con rollback to. Esto permite deshacer parte de una excepción.

SET TRANSACTION READ ONLY: Establece el comienzo de una transacción de solo lectura. Se utiliza para garantizar la consistencia de los datos recuperados entre distintas consultas. Todas las consultas que se ejecuten a continuación solo verán aquellos cambios confirmados antes del comienzo de la transacción.

Ejercicio. Que seleccione cuantas ventas tiene el cliente uno y cuantas el num=2;

Hasta el momento hemos visto el uso de cursores para seleccionar datos, pero también se puede utilizar el nombre del cursor que apunta a una fila para realizar una operación de actualización de esa fila. La declaración será la siguiente:

Cursor nombre_cursor IS SELECT FOR UPDATE;

For update indica que las filas seccionadas por el cursor van a ser actualizadas o borradas. Todas las filas seleccionadas, serán bloqueadas tan pronto se abra el cursor con open, y serán desbloquedas al terminar las actualizaciones, es decir al ejecutar un commit implícitamente o explícitamente.

Un vez incluido el cursor para update se incluirá el especificador:

CURRENT OF nombre_cursor en la claúsula where para actualizar la ultima fila recuperada mediante la orden fetch.

UPDATE/DELETE ..... WHERE CURRENT OF nombre_cursor

Actualizar el precio de venta de todos loa articulos para aquellos articulos de color indicado en la llamada. El precio será 10 veces más.modifica_pv

create or replace procedure modifica_pv(color articulos.art_col%type)

iscursor modifica is select art_pv from articuloswhere art_col=color for update;

/*COMO VEMOS EL PUNTERO SE POSICIONA EN LA/S FILAS PERTINENTES

precio articulos.art_pv%type;beginopen modifica;

fetch modifica into precio;while modifica%found loop

update articulosset art_pv=precio *10

where current of modifica;

Prácticas de diseño y gestión de bases de datos 15

Page 16: Tema 18 Cursores

Tema 18 Cursores, excepciones y control de transacciones en PL/SQL

fetch modifica into precio;end loop;

close modifica;

end;/

SQL> @modifica_pvInput truncated to 1 characters

Procedure created.

SQL> exec modifica_pv('ROJO');

PL/SQL procedure successfully completed.

SQL> SELECT * FROM ARTICULOS;

ART_NUM ART_NOM ART_PESO ART_COL ART_PC ART_PV ART_PRV

--------- -------------------- --------- ---------- --------- --------- --------- 1 IMPRESORA 150 ROJO 400 5800

4 2 CALCULADORA 150 NEGRO 4000

4700 1 3 CALENDARIO 100 BLANCO 420 600

4 4 LAMPARA 550 ROJO 2100 29800

5 5 LAMPARA 550 BLANCO 2000 2900

5 6 LAMPARA 550 AZUL 2100 2980

5 7 LAMPARA 550 VERDE 2100 2980

5 8 PESCARTAS 1-500 2400 4000

3 9 PESCARTAS 1-1000 3000 5000

3 10 BOLIGRAFO 20 ROJO 20 400

2 11 BOLIGRAFO 20 AZUL 20 40

2 12 BOLIGRAFO LUJO 20 ROJO 60 1000

2 13 BOLIGRAFO LUJO 20 VERDE 60 100

2 14 BOLIGRAFO LUJO 20 AZUL 60 100

2 15 BOLIGRAFO LUJO 20 NEGRO 60 100

2 20

Prácticas de diseño y gestión de bases de datos 16

Page 17: Tema 18 Cursores

Tema 18 Cursores, excepciones y control de transacciones en PL/SQL

16 rows selected.

Si la consulta del cursor hace referncia a muchas tablas, se deberá utilizar for update of <nombre_columna>, con lo que unicamente se bloquearan las filas correspondientes de la tabla que contenga la columnaq especificada.

CURSOR <nombre_cursor> IS SELECT ... FOR UPDATE OF<nombre_columna>.

Uso de rowid en lugar de for Update.

La utilización de update plantea situaciones problemáticas. Por ejemplo si ejecutamos un commit, después ya no podemos utilizar un fetch; para evitar este problema, utilizaremos el rowid que indicara la fila que se va a actualizar enlugar de for update. Para ello al declarar el cursor en la cláusula select indicaremos que seleccione tb el id de fila ó rowid.

CURSOR nombre_cursor IS SELECT....ROWID FROM TABLA;

Al ejecutar el fetch se guardra el numerode fila en una variable y después ese numero se podrá utilizar en la actualización.

Update|delete ..... where rowid=variable;

Con el rowid:

create or replace procedure modifica_pv(color articulos.art_col%type)is

cursor modifica is select art_pv,rowid from articuloswhere art_col=color;

variable modifica%rowtype;’DECLARAMOS UNA VARIABLE DEL TIPO DEL CURSORbeginopen modifica;

fetch modifica into variable;while modifica%found loop

update articulosset art_pv=art_pv *10

where rowid= variable.rowid;’CONDICION LA FILA SEA A LA QUE SE HACE REFERENCIA EN MEMORIA

fetch modifica into variable;end loop;

dbms_output.put_line('Han sido actualizadas '||modifica%rowcount||' filas');close modifica;end;/

Prácticas de diseño y gestión de bases de datos 17

Page 18: Tema 18 Cursores

Tema 18 Cursores, excepciones y control de transacciones en PL/SQL

17.-Ejercicios

1.-Desarrollar un procedimiento que visualice el apellido y la fecha de alta de todos, ordenados por apellido.

2.-Procedimiento que muestre los nombres de cada departamento y los empleados que tiene.

3.- Procedimiento que recibe una cadena y visualice el apellido y el numero de empleados, de todos los empleados que contengan la cadena especificada. AL finalizar visualizar el numero de empleados mostrados.

4.-Programa que visualice el apellido y el salario de los 5 empleados que tiene el salario mas alto.

5.- Que visualice los dos empleados que ganan menos dinero de cada oficio.

6.-Programa que muestre a)para cada empleado: apellido y salario.b)por cada departamento: numero de empleados y suma de los

salarios del departamento.c)Numero total de empleados y suma total de los salarios.

7.- Que permita insertar nuevos departamentos según las next especificaciones:

a. Se pasará al procedimiento el nombre del departamento y la localidad

a. b. El procedimiento insertará la fila nueva, asignando con numero de departamento la decena siguiente al numero mayor de la tabla.

b. Se incluirá la gestión de posible errores.

8.Procedimiento que reciba los datos de un new empleado y procese la transacción de alta, gestionando posibles errores.

9.Procedimiento que reciba como parámetros un número de departamento, importe y un porcentaje, y que suba el salario a todos los empleados del departamento indicado en la llamada. La subida será el porcentaje o importe que se indica en la llamada, el que sea más beneficioso para el empleado en cada caso.

10. Procedimiento que suba el sueldo de todos los empleados que ganen menos que el salario medio de su oficio. La subida será del 50% de la diferencia entre el salario del empleado y la media de su oficio. Se deberá hacer que la transacción no se quede a media y se gestionarán los posibles errores.

Prácticas de diseño y gestión de bases de datos 18

Page 19: Tema 18 Cursores

Tema 18 Cursores, excepciones y control de transacciones en PL/SQL

11.Diseñar una aplicación que simule un listado de liquidación de los empleados, según las siguientes especificaciones:Liquidación empleado...(1)Oficio........(3)Salario........(4)Trienios......(5)complemento responsabilidad......(6)Comisión ..............(7)

Total (8)

1,2,3,4, corresponden a apellidos, departamento, oficio y salario del empleado.

5. Es el importe en concepto de trienios. Un trienio son tres años completos, desde la fecha de alta hasta de emisión, y supone 5000 ptas.

6 Es el complemento por responsabilidad. Será de 10000 por cada empleado que se encuentre directamente a cargo del empleado en cuestión.

7 Comisión. Los valores nulos serán sustituidos por 0.

8 Es la suma de todos los conceptos anteriores.

El listado será ordenado por apellidos.

12.-Crear la tabla t_liquidación con las columnas apellido, departamento, oficio, salario, trienios, comp._responsabilidad , comisión, total y modificar la aplicación anterior para que en lugar de realizar el listado directamente en pantalla, guarde los datos en la tabla. Se controlaran todos los errores.

Prácticas de diseño y gestión de bases de datos 19