Está en la página 1de 18

TEMA 18: CURSORES, EXCEPCIONES Y CONTROL DE TRANSACCIONES EN PL/SQL 18.

1 Cursores Hasta el momento hemos venido usando cursores implcitos, este tipo de cursores es muy sencillo pero plantea un problema: La subconsulta debe devolver una fila y slo una, de lo contrario, se producira un error. Por ello dado que normalmente una consulta devolver varias filas, se suelen manejar cursores explcitos. 18.2 Cursores explcitos Se utilizan para trabajar con consultas que pueden devolver mas de una fila. Hay 4 operaciones bsicas para trabajar con un cursor explicito: 1) Declaracin del cursor: el cursor se declara en la zona de declaraciones segn la siguiente sintaxis: CURSOR <nombre_cursor> IS <sentencia SQL>; 2) Apertura del cursor: en la zona de instruccin habr que abrir el cursor. OPEN <nombre_cursor>; 3) Recogida de informacin: para recoger la informacin almacenada en el cursor, usaremos la siguiente sintaxis: FETCH <nombre_cursor> INTO {<variable>| <lista_variable>}; Despus del INTO aparecer una variable que guardara la informacin de todas las columnas. En este caso la variable puede ser declarada. <variable> <nombre_cursor>%ROWTYPE o una lista de variable. Cada una recoger la columna correspondiente a la columna SELECT por lo tanto sern del mismo tipo de las columnas. Cada FETCH lo que hace es recuperar una fila, y el cursor avanza automticamente a la siguiente fila. 4) Cierre del cursor: cuando el cursor no se va a utilizar hay que cerrarlo. CLOSE <nombre_cursor>; Ejemplo: visualizar el nombre y apellido de todos los clientes DECLARE CURSOR CURSOR_CLIENTE IS SELECT CLT_NOM,CLT_APELL FROM CLIENTES; -- DECLARACIN CURSOR

NOMBRE CLIENTES.CLT_NOM%TYPE; APELLIDO CLIENTES.CLT_APELL%TYPE; BEGIN OPEN CURSOR_CLIENTE; -- APERTURA DEL CURSOR FETCH CURSOR_CLIENTE INTO NOMBRE,APELLIDO; -- RECOGIDA DE DATOS WHILE CURSOR_CLIENTE%FOUND LOOP DBMS_OUTPUT.PUT_LINE(NOMBRE||APELLIDO); FETCH CURSOR_CLIENTE INTO NOMBRE,APELLIDO; END LOOP; CLOSE CURSOR_CLIENTE; -- CERRAR CURSOR END; / A diferencia de lo que ocurre con los cursores implcitos, la clusula INTO no aparece con la SELECT, sino que aparece en FETCH 18.3. Atributos de cursores Para conocer los detalles la situacin del cursor, hay 4 atributos para consultar: 1) %FOUND, devuelve verdadero si el ultimo FETCH ha recuperado algn valor. En caso contrario devuelve falso. Si el cursor no esta abierto devuelve error. Y si estaba abierto y no se haba ejecutado aun ningn FETCH devuelve NULL. Se puede utilizar como condicin de continuacin en bucles para recuperar informacin. 2) %NOTFOUND, se suele utilizar como una condicin de salida de bucles EXIT WHEN <nombre_cursor>%NOT FOUND; 3) %ROWCOUNT, devuelve el numero de filas recuperadas hasta el momento por el cursor. 4) %ISOPEN, devuelve verdadero si esta abierto. 18.4 Variables de acoplamiento en el manejo de cursores En una SELECT para introducir una condicin usamos un WHERE, en PL/SQL se puede usar un diseo mas abierto porque los trminos exactos de esa condicin se conocen en tiempos de ejecucin.

Ejemplo: consultar los clientes que viven en una determinada ciudad, mediante un procedimiento cuyo nombre es VIVEN_EN. CREATE OR REPLACE PROCEDURE VIVEN_EN(A CLIENTES.CLT_POB%TYPE) IS CURSOR CURSOR_POB IS SELECT CLT_NOM FROM CLIENTES WHERE CLT_POB=A; -- DECLARACION CURSOR VAR CLIENTES.CLT_NOM%TYPE; BEGIN OPEN CURSOR_POB; -- APERTURA DEL CURSOR FETCH CURSOR_POB INTO VAR; -- RECOGIDA DE VARIABLE WHILE CURSOR_POB%FOUND LOOP DBMS_OUTPUT.PUT_LINE(VAR); FETCH CURSOR_POB INTO VAR; END LOOP; CLOSE CURSOR_POB; -- CERRAR CURSOR END; / Le pasamos Madrid: VIVEN_EN('MADRID'); Que dara: Miguel Diego Joaquin PL/SQL procedure successfully completed. Para obtener todos los datos utilizaramos el %ROWTYPE de la siguiente forma: CREATE OR REPLACE PROCEDURE VIVEN_EN(A CLIENTES.CLT_POB%TYPE) IS CURSOR CURSOR_POB IS SELECT * FROM CLIENTES WHERE CLT_POB=A; -- DECLARACION CURSOR VAR CLIENTES%ROWTYPE;

BEGIN OPEN CURSOR_POB; -- APERTURA DEL CURSOR FETCH CURSOR_POB INTO VAR; -- RECOGIDA DE VARIABLE WHILE CURSOR_POB%FOUND LOOP DBMS_OUTPUT.PUT_LINE(VAR.CLT_NOM||VAR.CLT_APELL); FETCH CURSOR_POB INTO VAR; END LOOP; CLOSE CURSOR_POB; -- CERRAR CURSOR END; / Le pasamos Madrid: EXEC VIVEN_EN('MADRID'); Que dara: Miguel PEREZ Diego CORTES Joaquin FERNANDEZ PL/SQL procedure successfully completed. 18.5 Cursor FORLOOP Hasta ahora hemos visto que el trabajo del cursor consiste en lo siguiente: 1) Declarar el cursor. 2) Declarar una variable que recoja los datos del cursor. 3) Abrir el cursor. 4) Recuperar con FETCH una a una las filas extradas introduciendo los datos en las variables. 5) Cerrar el cursor. PL/SQL proporciona la estructura del cursor FOR...LOOP, que simplifica estas tareas realizando stas excepto la declaracin del cursor. FOR <nombre_variable> IN <nombre_cursor> LOOP <Instrucciones>; END LOOP; Ejemplo: obtener todos los clientes que son una determinada nacionalidad.

CREATE OR REPLACE PROCEDURE VER_NAC(A CLIENTES.CLT_PAIS%TYPE) IS CURSOR CURSOR_NAC IS SELECT * FROM CLIENTES WHERE CLT_PAIS=A; BEGIN FOR LINEA IN CURSOR_NAC LOOP DBMS_OUTPUT.PUT_LINE(LINEA.CLT_NOM||LINEA.CLT_APELL); END LOOP; END; / Le pasamos un parmetro: EXEC VER_NAC('E'); Que dara: Margarita BORRAS Miguel PEREZ Antoni LLOPIS Pablo GOI Consuelo ROMAN Pau ROCA Jorge MANCHA Pablo CURRO Diego CORTES Joaquin FERNANDEZ Jacinto DURAN Pedro MINGUIN B A PL/SQL procedure successfully completed. La variable se declara implcitamente con lo que no hace falta declararla, al salir del bucle la variable no estar disponible. 18.6 Uso de alias en las columnas de seleccin del cursor Cuando las columnas son expresiones usaremos alias. Ejemplo: si queremos calcular que dinero ha vendido cada tienda.

DECLARE CURSOR CUR_TIENDA IS SELECT VNT_TDA,SUM(VNT_CANT*VNT_PRECIO) TOTAL FROM VENTAS GROUP BY VNT_TDA; BEGIN FOR FILA IN CUR_TIENDA LOOP DBMS_OUTPUT.PUT_LINE (FILA.VNT_TDA||' ' ||FILA.TOTAL); END LOOP; END; / 18.7 Cursores con parmetros Un cursor puede tener parmetros y que tendrn el siguiente parmetro: CURSOR nombre_cursor [(parametro1,parametro2,...)] IS SELECT <sentencia select en la que intervendrn los parmetros>; Los parmetros formales indicados despus del nombre del cursor, tienen la siguiente sintaxis: Nombre_variable [IN] tipo_dato [{:= | DEFAULT } VALOR] Todos los parmetros formales de un cursor son parmetros de entrada. El mbito de estos parmetros es local al cursor, por eso solo pueden ser referenciados dentro de la consulta. Ejemplo: usar un cursor pasndole un parmetro que ser el nombre del cliente. DECLARE CURSOR CUR_NUM(A CLIENTES.CLT_NUM%TYPE) IS SELECT CLT_NOM FROM CLIENTES WHERE CLT_NUM=A; VAR CLIENTES.CLT_NOM%TYPE; BEGIN OPEN CUR_NUM(1); FETCH CUR_NUM INTO VAR; DBMS_OUTPUT.PUT_LINE(VAR); END; /

Que dara: Input truncated to 1 characters Margarita PL/SQL procedure successfully completed. Ejemplo: hallamos los clientes que viven en Espaa DECLARE CURSOR CUR_PAIS(A CLIENTES.CLT_PAIS%TYPE) IS SELECT CLT_NOM FROM CLIENTES WHERE CLT_PAIS=A; VAR CLIENTES.CLT_NOM%TYPE; BEGIN OPEN CUR_PAIS('E'); FETCH CUR_PAIS INTO VAR; WHILE CUR_PAIS%FOUND LOOP DBMS_OUTPUT.PUT_LINE(VAR); FETCH CUR_PAIS INTO VAR; END LOOP; CLOSE CUR_PAIS; END; / Que dara: Input truncated to 1 characters Margarita Miguel Antoni Pablo Consuelo Pau Jorge Pablo Diego Joaquin Jacinto Pedro B PL/SQL procedure successfully completed.

18.8 Atributos en cursores implcitos Oracle abre implcitamente un cursor cuando procesa un comando SQL que no este asociado a un cursor explcito. El cursor implcito dispone tambin de los 4 atributos mencionados que pueden facilitarnos informacin sobre la ejecucin de los comandos SELECT INTO,INSERT,UPDATE y DELETE. Los cursores cuando son implcitos se llaman SQL, sus atributos serian: 1) %NOTFOUND, dar TRUE si el ultimo INSERT, UPDATE, DELETE o SELECT INTO ha fallado. 2) %FOUND, que dar TRUE si el ultimo NSERT, UPDATE, DELETE o SELECT INTO han afectado a alguna de las filas. 3) %ROWCOUNT, devuelve el numero de filas afectadas por el ultimo NSERT, UPDATE, DELETE o SELECT INTO. 4) %ISOPEN, siempre devolver falso ya que Oracle cierra automticamente el cursor despus de casa orden SQL. Notas a tener en cuenta: a) El comportamiento de los atributos en los cursores implcitos es diferente al de los cursores explcitos. En los implcitos, el cursor se cierra tras procesar la orden SELECT INTO. b) Devolver un valor relativo a la ultima orden INSERT, UPDATE, DELETE 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 podr levantar un error. NO_DATA_FOUND sino devuelve nada. TOO_MANY_ROWS si devuelve mas de una fila. d) Lo indicado en el prrafo anterior no es aplicable a INSERT, UPDATE y DELETE. Ejemplo: Comprobar que se da cuando se ejecuta un UPDATE y no devuelve dato, que se provoca, la excepcin o que no se ha encontrado el dato (NOTFOUND)? DECLARE POBLACION CLIENTES.CLT_POB%TYPE; CLIENTE CLIENTES%ROWTYPE; BEGIN POBLACION :='MALAGA'; UPDATE CLIENTES SET CLT_POB = POBLACION WHERE CLT_POB= 'SEVILLA'; IF (SQL%NOTFOUND) THEN

DBMS_OUTPUT.PUT_LINE('NO SE HA ENCONTRADO DATOS NOT_FOUND'); END IF; SELECT * INTO CLIENTE FROM CLIENTES WHERE CLT_POB='MALAGA'; EXCEPTION WHEN NO_DATA_FOUND THEN DBMS_OUTPUT.PUT_LINE('DATOS NO ENCONTRADOS NO_DATA_FOUND'); END; / Que dara: Input truncated to 1 characters DATOS NO ENCONTRADOS NO_DATA_FOUND PL/SQL procedure successfully completed. Por lo que salta la excepcin antes. Cuando un SELECT INTO hace referencia a una funcin de grupo nunca se levantara la excepcin NO_DATA_FOUND y SQL%FOUND siempre ser verdadero, ello es debido a que las funciones, ello es debido a que las funciones retornan siempre un valor aunque sea NULL. 18.9 Excepciones Las excepciones sirven para tratar errores en tiempo de ejecucin, as como errores y situaciones definidas por el usuario, cuando se produce un error PL/SQL levanta una excepcin y pasa el control de la excepcin a la seccin EXCEPTION, que actuara segn lo establecido y dar por finalizado el bloque actual. Sintaxis: EXCEPTION WHEN <nombre_excepcion1> THEN <instruccion1>; WHEN <nombre_excepcion2> THEN <instruccion2>;

.............. [WHEN OTHERS <instrucciones>;] END nombre_programa; / Tipos de excepciones: 1) Excepciones internas 2) Excepciones definidas por el usuario 3) Otras excepciones. 18.10 Excepciones internas predefinidas Estas excepciones estn predefinidas en Oracle. Se disparan automticamente al producirse determinados errores. Estas excepciones no hay que declararlas en la seccin DECLARE (las propias se declaran en esta seccin). 18.11 Excepciones definidas por el usuario Pasos: 1) Se deben declarar en la seccin DECLARE de la siguiente forma: <nombre_excepcion> EXCEPTION; 2) Se disparan en la seccin EJECUTABLE del programa con la orden RAISE: RAISE <nombre_excepcion>; 3) Se tratan en la seccin EXCEPTION segn el formato conocido ya: WHEN <nombre_excepcion> THEN <tratamiento>; Ejemplo: Seleccionar el precio de venta del artculo numero 1, si el precio de venta es mayor que 100 saltara la excepcin mayor_100 y sino salta a la excepcin menor_igual_100. DECLARE CURSOR CUR_ARTICULO IS SELECT ART_PV FROM ARTICULOS WHERE ART_NUM=1; VAR ARTICULOS.ART_PV%TYPE; MAYOR_100 EXCEPTION;

MENOR_IGUAL_100 EXCEPTION; BEGIN OPEN CUR_ARTICULO; FETCH CUR_ARTICULO INTO VAR; CLOSE CUR_ARTICULO; IF VAR>100 THEN RAISE MAYOR_100; ELSE RAISE MENOR_IGUAL_100; END IF; EXCEPTION WHEN MAYOR_100 THEN DBMS_OUTPUT.PUT_LINE(VAR||' ES MAYOR QUE 100'); WHEN MENOR_IGUAL_100 THEN DBMS_OUTPUT.PUT_LINE(VAR||' ES MENOR O IGUAL A 100'); END; / Que dara: 580 ES MAYOR QUE 100 PL/SQL procedure successfully completed. Input truncated to 1 characters 18.12 Otras excepciones Existen otros tipos de errores internos de Oracle similares a los asociados a las excepciones internas, pero no tienen asignada una excepcin, sino un cdigo de error y un mensaje de error, que se accede mediante las funciones SQLCODE y SQLERRM. Cuando se producen unos de estos errores se transfieren el control a la seccin EXCEPTION donde se tratara el error con la clusula WHEN OTHERS.

tambin podemos asociar una excepcin a algunos de los errores internos que no tienen excepciones predefinidas asociadas. Para ello procederemos as: 1) Definimos una excepcin en la seccin de declaraciones, como si fuera definida por el usuario. <nombre_excepcion> EXCEPTION; 2) Asociamos esa excepcin a un determinado cdigo mediante la directiva del compilador (va en la seccin DECLARE). PRAGMA EXCEPTION_INIT(<nombre_excepcion>,<numero_error_Oracle>); 18.13 Propagacin y mbito de las excepciones La gestin de excepciones en PL/SQL tiene unas reglas que se deben considerar en el diseo de aplicaciones: a) Cuando se levanta una excepcin, el programa bifurca a la seccin EXCEPTION del bloque actual, sino esta definida en ella, la excepcin se programa al bloque que llamo al bloque actual, pasando el control a la seccin EXCEPTION de dicho bloque y as sucesivamente. b) Una vez tratada la excepcin en un bloque se devuelve el control al bloque que llamo al que trato la excepcin. c) Si despus de tratar una excepcin queremos volver a la lnea siguiente a la que se produjo no podemos hacerlo directamente. d) La clusula WHEN OTHERS tratara cualquier excepcin que no aparezca en las clusulas WHEN correspondientes con independencia del tipo de excepcin. De este modo se evitara que la clusula se propague a los bloques de nivel superior. 18.14 Utilizacin de RAISE_APPLICATION_ERROR En el paquete de DBMS estndar se incluye un procedimiento RAISE_APPLICATION_ERROR que sirve para levantar errores y definir y enviar mensajes de error. Su sintaxis es: RAISE_APPLICATION_ERROR (numero_error,mensaje) Numero de error es un numero comprendido entre 20000..-20999. Mensaje de error es una cadena de 512 bytes. Cuando un programa hace esta llamada se levanta la excepcin y se deshacen los cambios realizados por ese programa. Ejemplo: Crear un procedimiento que se llame subir precio, que se le pasara como parmetro el numero del articulo y el incremento a subir (art_pv), debe hacer un UPDATE y si hubiese un error debera devolver precio nulo, si sale error mostrar su mensaje de error.

CREATE OR REPLACE PROCEDURE SUBIR_PRECIO(A ARTICULOS.ART_NUM %TYPE,B ARTICULOS.ART_PV%TYPE) IS PRECIO ARTICULOS.ART_PV%TYPE; BEGIN SELECT ART_PV INTO PRECIO FROM ARTICULOS WHERE ART_NUM=A; IF PRECIO IS NULL THEN RAISE_APPLICATION_ERROR(-20005,'PRECIO NULO'); ELSE PRECIO:= PRECIO + B; UPDATE ARTICULOS SET ART_PV=PRECIO WHERE ART_NUM=A; DBMS_OUTPUT.PUT_LINE('SE HA ACTUALIZADO'); END IF; END; / Que dara: BEGIN subir_precio (20,22); END; * ERROR at line 1: ORA-20005: PRECIO NULO ORA-06512: at "FORM.SUBIR_PRECIO", line 12 ORA-06512: at line 1 18.5 Control de transacciones Una transaccin se puede definir como un conjunto de operaciones que se realizan en la base de datos. En una transaccin es el usuario quien decide cuales sern las operaciones que compondrn la transaccin. Oracle garantiza la consistencia de datos en una transaccin de trminos vale todo o no vale nada, es decir, o se ejecutan todas las operaciones que componen la transaccin o no se ejecuta ninguna. As pues la base de datos tiene un estado antes de la transaccin y un estado despus de la transaccin, pero no hay estados intermedios. Una transaccin en PL/SQL comienza con la 1 orden SQL de la sesin de usuario o con la 1 orden SQL posterior a la finalizacin de la transaccin anterior. La transaccin finaliza cuando se ejecuta un comando de control de transacciones (como el COMMIT o el ROLLBACK), una orden DDL o cuando finaliza la sesin.

Comandos: COMMIT WORK, da por concluida la transaccin actual y hace definitivos los cambios efectuados liberando las filas bloqueadas. Solo despus de que se ejecute un COMMIT los usuarios tendrn acceso a los datos modificados. ROLLBACK WORK, da por concluida la transaccin actual y deshace los cambios que se pudieran haber producido en la base de datos liberando las filas bloqueadas. Se utiliza especialmente cuando no se puede concluir una transaccin porque se levanta la excepcin. SAFEPOINT, se usa para poner marcas o puntos de salva guarda al procesar transacciones, se usa en conjuncin con ROLLBACK TO, esto permite deshacer parte de una transaccin SET TRANSACTION READ ONLY, establece el comienzo de una transaccin de solo lectura. Se utiliza para garantizar la consistencia de los datos recuperados entre las distintas consultas. Todas las consultas que se ejecuten a continuacin slo vern aquellos cambios confirmados antes del comienzo de la transaccin. EJERCICIOS: 1. Desarrollar un procedimiento que visualice los apellidos y la fecha de alta de todos los empleados ordenados por apellido. CREATE OR REPLACE PROCEDURE APEL_FECHA IS CURSOR CUR_EMPLE IS SELECT APELLIDO,FECHA_ALT FROM EMPLE ORDER BY APELLIDO; BEGIN FOR FILA IN CUR_EMPLE LOOP DBMS_OUTPUT.PUT_LINE(FILA.APELLIDO|| ' ' || FILA.FECHA_ALT); END LOOP; END; / 2. Codificar un procedimiento que muestre el nombre de cada departamento y el numero de empleados que tiene.

3. Escribir un procedimiento que reciba una cadena y visualice el apellido y el numero del empleado de todos los empleados cuyo apellido contenga la cadena especificada. Al finalizar, visualizar el numero de empleados mostrados. 4. Escribir un programa que visualice el apellido y el salario de los 5 empleados que tiene el salario mas alto. 5. Codificar un programa que visualice los 2 empleados que ganan menos dinero de cada oficio. 6. Escribir un programa que muestre por: a) Cada empleado, el apellido y salario. b) Por cada departamento, numero de empleados y suma de los salarios del departamento. c) Al final del listado numero total de empleados y suma de todos los salarios. 7. Desarrollar un procedimiento que permita insertar un nuevo departamento segn las siguientes especificaciones: a) Se pasaran al procedimiento el nombre del departamento y la localidad. b) El procedimiento insertara la fila nueva asignando como nmero de departamento la decena siguiente al nmero mayor de la tabla. c) Se incluir la gestin de posibles errores. 8. Escribir un procedimiento que reciba todos los datos de un nuevo empleado y procese la transaccin de alta, gestionando posibles errores. 9. Codificar un procedimiento que reciba como parmetros un numero de departamentos, un 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 el importe que se indica en la llamada, el que sea ms beneficioso para el empleado en cada caso. 10. Escribir un 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 transaccin no se quede a medias, y se gestionaran los posibles errores. 11. Disear una aplicacin que simule un listado de liquidacin de los empleados segn las siguientes especificaciones: *********** ******* liquidacin empleado...(1) departamento...(2) oficio......(3) salario.....(4) trienios...(5) composicin responsabilidad....(6)

comisin...(7) (18) ----*************

*********

1,2,3 corresponden a apellido, departamento, oficio y salario del empleado 5 es el importe en importe de trienios, que son 3 aos completos desde la fecha de alta hasta la de emisin y suponen 5.000 pesetas. 6 es el complemento por responsabilidad, ser de 10.000 pts por cada empleado que se encuentre directamente a cargo del empleado en cuestin. 7 la comisin, los valores nulos sern substituidos por ceros. 8 es la suma de todos los conceptos anteriores, el listado ser ordenado por apellidos. 12. Crear la tabla t_liquidacin con las columnas apellido, departamento, oficio, salario, trienios, compensacin de responsabilidad, comisin y total. Y modificar la aplicacin anterior para que, en lugar de realizar el listado directamente en pantalla guarde los datos en la tabla, se controlaran todas las posibles incidencias que puedan ocurrir durante el proceso. 18.16 Uso de cursores para actualizar filas Hasta el momento hemos visto el uso del cursor para seleccionar datos, pero tambien se puede usar el nombre del cursor que apunta a una fila para realizar una operacin de actualizacion de filas. La declaracin sera la siguiente: CURSOR nombre_cursor <declaracin_cursor> FOR UPDATE FOR UPTADE indica que las filas seleccionadas por el cursor van a ser actualizadas o borradas todas las filas seleccionadas seran bloqueadas tan pronto se habra el cursor con open y seran desbloqueadas al terminar las actualizaciones, es decir al usar un COMMIT. Una vez declarado el cursor con UPDATE se incluira el especificador CURRENT OF nombre_del cursor en la clausula WHERE para actualizar UPDATE, borrar DELETE la ultima fila mediante la orden FETCH. {UPDATE | DELETE }... WHERE CURRENT OF nombre_cursor; Ejemplo: Actualizar el precio de venta de todos los articulos para aquellos articulos de color indicado en la llamada, el nuevo precio es multiplicado por 10. El nombre del procedimiento es MODIFICAR_PV. CREATE OR REPLACE PROCEDURE MODIFICAR_PV(A ARTICULOS.ART_COL %TYPE) IS

CURSOR CUR_PV IS SELECT ART_PV FROM ARTICULOS WHERE ART_COL=A FOR UPDATE; BEGIN FOR I IN CUR_PV LOOP UPDATE ARTICULOS SET ART_PV= ART_PV*10 WHERE CURRENT OF CUR_PV; END LOOP; END; /

Compilamos: SQL> @PL24 Procedure created. Le pasamos el parmetro: SQL> EXEC MODIFICAR_PV('NEGRO'); Que daria: PL/SQL procedure successfully completed. Si en la consulta del cursor hace referencia a multiples tablas, se debera usar FOR UPDATE OF nombre_columna con lo que unicamente se bloquearan las filas correspondientesde la tabla que cotenga la columna especificada. Sintaxis: CURSOR nombre_cursor < declaracin_cursor> FOR UDATE OF nombre_columna Uso de ROWID en lugar de FOR UPDATE La utilizacin de la clausula FOR UPDATE plantea algunas cuestiones que algunas veces que pueden ser problemticas, si se ejecuta un COMMIT despus no se puede usar un FETCH para evitarlo se usa ROWID que nos indicara el numero de fila que se va a actualizar. Para ello al declarar el cursor en la clausula SELECT indicaremos que seleccione tambien el identificador de filas o ROWID. CURSOR nombre_cursor IS SELECT col1,col2..., ROWID FROM tabla;

Al ejecutar el FETCH se guardara el numero de fila en una variable y despus ese numero se podra utilizar en la clausula WHERER en la actualizacion. {UPDATE | DELETE} ... WHERE ROWID = variable; Ejemplo: mismo ejercicio que antes. CREATE OR REPLACE PROCEDURE MODIFICAR_PV(A ARTICULOS.ART_COL %TYPE) IS CURSOR CUR_PV IS SELECT ART_PV,ROWID FROM ARTICULOS WHERE ART_COL=A; ID CUR_PV%ROWTYPE; BEGIN FOR I IN CUR_PV LOOP UPDATE ARTICULOS SET ART_PV= ART_PV*10 WHERE ROWID=ID.ROWID; END LOOP; END; / Compilamos: SQL> @PL25 Procedure created. Le pasamos el parmetro: SQL> EXEC MODIFICAR_PV('NEGRO'); Que daria: PL/SQL procedure successfully completed.