Cómo utilizar un cursor PL/SQL como parámetro de salida en un procedimiento
En este artículo o voy a proponer un ejercicio práctico bastante sencillo que puede resultar de bastante útilidad práctica. Supongamos que queremos crear un procedimiento PLSQL que utilice un par de parámetros de entrada, que podrán tomar el valor NULL, y con un parámetro de salida que será el cursor PL/SQL correspondiente a la siguiente sentencia SELECT:
SELECT * FROM empleados
WHERE nombre = parametro_1
AND apellidos = parametro_2;
Lo primero que tendremos que hacer es crear un paquete PL/SQL que contenga la definición del cursor:
CREATE OR REPLACE PACKAGE empleados_pkg
IS
/* Definición del REF CURSOR type */
TYPE empleados_type IS REF CURSOR
RETURN empleados%ROWTYPE;
END empleados_pkg;
Después sólo tendremos que crear el procedimiento PLSQL que devolverá como salida el cursor definido en el paso anterior, y que utilizará los dos parámetros de entrada indicados en el enunciado del problema que estamos intentando resolver.
CREATE OR REPLACE PROCEDURE datos_empleados
(
par1 IN VARCHAR2,
par2 IN VARCHAR2,
cursor1 OUT empleados_pkg.empleados_type
)
AS
BEGIN
OPEN cursor1 FOR
SELECT * FROM empleados
WHERE nombre = NVL(par1,nombre)
AND apellidos = NVL(par2,apellidos);
END datos_empleados;
No obstante, la utilización de la función NVL (si par1 es NULL toma el valor nombre, si par2 es NULL toma el valor apellidos), podría no ser muy conveniente y derivar en problemas de rendimiento, por lo que es recomendable definir el procedimiento anterior como sigue:
CREATE OR REPLACE PROCEDURE datos_empleados
(
par1 IN VARCHAR2,
par2 IN VARCHAR2,
cursor1 OUT empleados_pkg.empleados_type
)
AS
BEGIN
/* Todos los parámetros tienen valor */
IF par1 IS NOT NULL AND par2 IS NOT NULL
THEN
OPEN cursor1 FOR
SELECT * FROM empleados
WHERE nombre = par1
AND apellidos = par2;
/* Sólo tiene valor par1 */
ELSIF par1 IS NOT NULL
THEN
OPEN cursor1 FOR
SELECT * FROM empleados
WHERE nombre = par1;
/* Sólo tienen valor par2 */
ELSIF par2 IS NOT NULL
THEN
OPEN cursor1 FOR
SELECT * FROM empleados
WHERE apellidos = par2;
/* Ningún parámetro tiene valor */
ELSE
THEN
OPEN cursor1 FOR
SELECT * FROM empleados;
END IF;
END datos_empleados;
Artículos relacionados: Cursores en PLSQL.



15 comentarios:
Hola, acabo de volver de vacaciones y justamente necesitaba esto.
Gracias de nuevo por tus artículos.
Tengo una pregunta al respecto:
En el caso de que quiera que el cursor que me devuelve la función no contenga todas las columnas de la table empleados, como tendría que definir el PACKAGE empleados_pkg?
Supongamos que quiero que el cursor contenga únicamente los campos apellidos y salario.
CREATE OR REPLACE PACKAGE empleados_pkg
IS
/* Definición del REF CURSOR type */
TYPE empleados_type IS REF CURSOR
RETURN (empleados.apellidos%TYPE, empleados.salario%TYPE);
END empleados_pkg;
¿Sería correcta esta sintaxis?
Hola Lom, sería como sigue:
CREATE OR REPLACE PACKAGE empleados_pkg IS
CURSOR c_emp IS
SELECT apellidos, salario
FROM empleados;
TYPE empleados_type IS REF CURSOR
RETURN c_emp%ROWTYPE;
END empleados_pkg;
Pregunta, en el primer caso, luego de correr el procedimiento, como utilizo el cursor creado por fuera del mismo?
Es decir, puedo en la misma sesiion hacer un select * from cursor1;
Gracias.
Gracias Pepelu por tu respuesta.
Daniel, en el procedimiento PL/SQL abro el cursor, sólo se necesita llamar al procedimiento y utilizar el comando FETCH para recoger los valores devueltos por el cursor. Te adjunto un ejemplo:
DECLARE
c_emp empleados_pkg.empleados_type;
c_emp_rec c_emp%ROWTYPE;
BEGIN
datos_empleados ('Pepe', 'Alegre', c_emp);
LOOP
FETCH c_emp INTO c_emp_rec;
EXIT WHEN c_emp%NOTFOUND;
DBMS_OUTPUT.PUT_LINE (c_emp_rec.salario);
END LOOP;
CLOSE c_emp;
END;
Hola, tengo una tabla como sigue:
DNI NOMBRE EDAD
--- ------------ ----
11 Juan Álvarez 18
Cómo puedo hacer lo siguiente:
crear un bloque PL/SQL, que pida por teclado el dni de la persona y que posteriormente se muestre el nombre y la edad de la persona correspondiente.
Gracias
Saludos
Iván
Hola Kraftcreme,
Tu pregunta no tiene mucho que ver con lo que se cuenta en este artículo y es algo bastante básico. De todas formas te adjunto un ejemplo de como debería ser el script PL/SQL que me pides:
DECLARE
-- Cursor para obtener el nombre y la edad
CURSOR obtener_nombre IS
SELECT
nombre,
edad
FROM
tabla_nombres
WHERE
dni = &1;
BEGIN
-- Obteniendo nombres con mismo DNI
FOR obtener_nombre_rec IN obtener_nombre LOOP
dbms_output.put_line ('Nombre '||obtener_nombre_rec.nombre);
dbms_output.put_line ('Edad '||obtener_nombre_rec.edad);
END LOOP;
END;
Buen articulo, me ha servido, y buen blog, he conseguido buena info de plsql aqui
salu2
esa es la manera 'primitiva' ahora se usa sys_refcursor. suerte , buen blog !!!
Marcos, tu comentario puede crear confusión. SYS_REFCURSOR se trata de un tipo REF CURSOR que viene predefinido desde la versión 9i de las bases de datos Oracle. Es cierto que se puede utilizar para lo que he explicado, pero tampoco abrevia demasiado el proceso.
pepelu, es excelente la informacion posteada aca,
ahora te pregunto, no se como invocar el store procedure desde visual basic 6 para poder utilizar justamente el cursor.
vos podras pasarme esa informacion?
gracias
Hola Lukaz, en este caso me has pillado porque no tengo ninguna experiencia con Visual Basic conectado a una base de datos Oracle.
Hola Pepelepu, pues tengo un pequeño problema, tenemos algunos Package en nuestra base de datos, pero los queremos llamar desde un ADF que esta echo en Jdeveloper, me podrias ayudar con esto, los procedimientos tambien nos devuelven cursores asi como los que posteaste, pero no sabemos como invocarlos desde Jdeveloper ADF
Ulises, echa un vistazo a esta página:
http://forums.oracle.com/forums/thread.jspa?threadID=841752
Publicar un comentario en la entrada