Comenzamos A Explicar Los Cursores de PL
Comenzamos A Explicar Los Cursores de PL
Comenzamos A Explicar Los Cursores de PL
4. - Cierre del cursor: CLOSE <nombrecursor>; Ahora, veamos un ejemplo de utilizacin de cursores explcitos: 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 declaracin de los cursores explcitos no utilizamos la clusula INTO, que s se utilizaba en los cursores implcitos. Ademas podis ver que despus 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 situacin del cursor tenemos 4 atributos:
%FOUND: devuelve verdadero di el ultimo FETCH ha recuperado algn 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 nmero de filas recuperadas hasta el momento. %ISOPEN: devuelve verdadero si el cursor esta abierto.
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 clusula WHERE se incluye una variable que se debera 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 seleccionarn las filas segn dicho valor. Aunque ese valor cambie durante la recuperacin 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;
2) Continuamos con los cursores de PL/SQL, esta vez vamos a ver variables de acoplamiento y cursores con parmetros.
Dando continuidad al Manual de Oracle que estamos publicando en DesarrolloWeb.com, y en el apartado del lenguaje PL/SQL, continuamos nuestras explicaciones sobre los cursores, que habamos comenzado a explicar en el artculo anterior. Variables de acoplamiento Si os fijis en el siguiente ejemplo veris que en la clusula 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 seleccionarn las filas segn 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 extradas introduciendo los datos en las variables, procesndolos 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 implcita, todas menos la declaracin del cursor. El formato y el uso de esta estructura es: 1. se declara la informacin cursor en la seccin 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 automtica, se declara implcitamente la variable nombreVarReg de tipo nombrecursor%ROWTYPE y se ejecuta el primer fetch cuyo resultado quedarn en nombreVarReg. A continuacin se realizaran las acciones que correspondas hasta llegar al END LOOP. Este es un ejemplo del LOOP . 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 parmetros Un cursor puede tener parmetros; en este caso se aplicara el siguiente formato genrico: CURSOR nombrecursor [(parmetros)] IS SELECT <sentencia select en la que intervendrn los parmetros>; Los parmetros formales indicados despus del nombre del cursor tienen la siguiente sintaxis: nombreCursor [IN] tipodato [{:=|DEFAULT} valor] Todos los parmetros formales de un cursor son parmetros de entrada y su mbito es local al cursor por eso slo 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 parmetros lo haremos de la siguiente forma: OPEN nombrecursor [(parmetros)];
3) Continuamos con los cursores, esta vez vamos a ver atributos con cursores explcitos y uso de cursores para actualizar filas.
Atributos con Cursores implcitos Los atributos de los cursores implcitos que se crean son los siguientes:
SQL%NOTFOUND: nos dice si el ltimo insert, update,delete o select into no han afectado a ninguna fila. SQL%FOUND: nos dice si el ltimo insert, update,delete o select into ha afectado a una o mas filas SQL%ROWCOUNT: devuelve el nmero de filas afectadas por el ltimo insert, update, delete o select into SQL%ISOPEN: Nos dice si el cursor esta cerrado, por lo que en teora siempre nos dar falso ya que Oracle cierra automticamente el cursor despus de cada orden SQL.
Es importante tener en cuenta una serie de cosas: Si se trata de un select into tenemos que tener en cuenta que solo puede devolver una nica fila de lo contrario nos levantar automticamente una de estas dos excepciones: NO_DATA_FOUND: si la consulta no devuelve ninguna fila TOO_MANY_ROWS: si la consulta devuelve ms de una fila
Cuando un select into hace referencia a una funcin de grupo nuca se levantar la excepcin NO_DATA_FOUND y SQL%FOUND siempre ser verdadero. Esto se explica porque las funciones de grupo siempre devuelven algn valor (NULL se considera un valor). Uso de cursores para actualizar filas Para realizar una actualizacin con un cursor tenemos que aadir la siguiente FOR UPDATE al final de la declaracin del cursor: CURSOR nombre_cursor <declaraciones> FOR UPDATE Esto indica que las filas seleccionadas por el cursor van a ser actualizadas o borradas. Una vez declarado un cursor FOR UPDATE, se incluir el especificador CURRENT OF nombre_cursor en la clusula WHERE para actualizar o borrar la ltima fila recuperada mediante la orden FETCH. {UPDATE|DELETE}... WHERE CURRENT OF nombre_cursor. Os pongo un ejemplo para que quede claro: Subir el salario a todos los empleados del departamento indicado en la llamada. El porcentaje se indicar tambin en la llamada. CREATE OR REPLACE PROCEDURE subir_salario (num_dept NUMBER, incre NUMBER) IS CURSOR c IS SELECT oficio, salario FROM empleados WHERE cod_dept=num_dept FOR UPDATE; reg c%ROWTYPE; inc NUMBER (8); BEGIN OPEN c; FETCH c INTO reg; WHILE c%FOUND LOOP inc :=(reg.salario/100 )* inc; UPDATE empleados SET salario=salario+inc WHERE CURRENT OF c FETCH c INTO reg; END LOOP; END;
Tambin podemos usar ROWID en lugar de FOR UPDATE. ROWID nos indicar la fila que se va a actualizar. Para ello, al declarar el cursor en la clusula SELECT indicaremos que seleccione tambin el identificador de fila: CURSOR nombre_cursor IS SELECT columna1,columna2,...ROWID FROM tabla; Al ejecutarse el FETCH se guardar el nmero de fila en una variable y despus ese nmero se podr usar en la clusula WHERE de la actualizacin: {UPDATE |DELETE } ... WHERE ROWID = variable_rowid El ejemplo anterior utilizando ROWID quedara de la siguiente manera: CREATE OR REPLACE PROCEDURE subir_salario (num_dept NUMBER, incre NUMBER) IS CURSOR c IS SELECT oficio, salario,ROWID FROM empleados WHERE cod_dept=num_dept FOR UPDATE; reg c%ROWTYPE; inc NUMBER (8); BEGIN OPEN c; FETCH c INTO reg; WHILE c%FOUND LOOP inc :=(reg.salario/100 )* inc; UPDATE empleados SET salario=salario+inc WHERE ROWID = reg.ROWID; FETCH c INTO reg; END LOOP; END; Con este artculo damos por terminado todo lo referente a cursores y empezamos a tratar las excepciones en el siguiente artculo.