pl/sql francisco moreno universidad nacional. subprogramas: procedimientos a excepción de los...
TRANSCRIPT
![Page 1: PL/SQL Francisco Moreno Universidad Nacional. Subprogramas: Procedimientos A excepción de los triggers, hasta ahora los bloques PL/SQL que se han presentado](https://reader033.vdocuments.pub/reader033/viewer/2022061611/5528bde3497959977d8f9d57/html5/thumbnails/1.jpg)
PL/SQLPL/SQLFrancisco Moreno
Universidad Nacional
![Page 2: PL/SQL Francisco Moreno Universidad Nacional. Subprogramas: Procedimientos A excepción de los triggers, hasta ahora los bloques PL/SQL que se han presentado](https://reader033.vdocuments.pub/reader033/viewer/2022061611/5528bde3497959977d8f9d57/html5/thumbnails/2.jpg)
Subprogramas: Procedimientos
• A excepción de los triggers, hasta ahora los bloques PL/SQL que se han presentado son– Anónimos (sin nombre) – Temporales (no quedan almacenados en la BD)
• Los bloques PL/SQL se pueden almacenar (garantizar su persistencia) en la BD mediante subprogramas (funcionesfunciones y procedimientosprocedimientos))
• Los subprogramas pueden tener argumentos (parámetros)
![Page 3: PL/SQL Francisco Moreno Universidad Nacional. Subprogramas: Procedimientos A excepción de los triggers, hasta ahora los bloques PL/SQL que se han presentado](https://reader033.vdocuments.pub/reader033/viewer/2022061611/5528bde3497959977d8f9d57/html5/thumbnails/3.jpg)
Procedimientos
Sintaxis:Sintaxis:
CREATE [OR REPLACE] PROCEDUREnombre_procedimiento[( arg1 [modo] tipo [, arg2 [modo]
tipo...])]IS | ASBloque PL/SQL
![Page 4: PL/SQL Francisco Moreno Universidad Nacional. Subprogramas: Procedimientos A excepción de los triggers, hasta ahora los bloques PL/SQL que se han presentado](https://reader033.vdocuments.pub/reader033/viewer/2022061611/5528bde3497959977d8f9d57/html5/thumbnails/4.jpg)
• La opción REPLACE remplaza el procedimiento si ya existe
• Se puede usar AS o IS (son equivalentes)• El bloque PL/SQL comienza con la
palabra BEGIN o con la declaración de las
variables locales (sin usar la palabra DECLARE).
• Para ver los errores de compilación en SQL*Plus se puede usar el comando SHOW ERRORS
Herramientas como SQL Navigator, PL/SQL Developer, entre otras; facilitan mucho las labores de depuración.
![Page 5: PL/SQL Francisco Moreno Universidad Nacional. Subprogramas: Procedimientos A excepción de los triggers, hasta ahora los bloques PL/SQL que se han presentado](https://reader033.vdocuments.pub/reader033/viewer/2022061611/5528bde3497959977d8f9d57/html5/thumbnails/5.jpg)
• El "modo" especifica el tipo del parámetro así:
- IN (modo predeterminado): Parámetro de entrada.
- OUT: Parámetro de salida. El subprograma devuelve un valor en el parámetro.
- IN OUT: Parámetro de entrada y salida. El subprograma devolverá un valor posiblemente diferente al enviado inicialmente.
• Para declarar los parámetros usar en lo posible %TYPE y %ROWTYPE
• No se puede especificar tamaño para los parámetros en lo que respecta al tipo de datos
![Page 6: PL/SQL Francisco Moreno Universidad Nacional. Subprogramas: Procedimientos A excepción de los triggers, hasta ahora los bloques PL/SQL que se han presentado](https://reader033.vdocuments.pub/reader033/viewer/2022061611/5528bde3497959977d8f9d57/html5/thumbnails/6.jpg)
Ejemplo 1. Sea la tabla:
CREATE TABLE registro( id_usuario VARCHAR2(10), fecha DATE, estacion VARCHAR2(15));
CREATE OR REPLACE PROCEDURE registrarse ISBEGIN INSERT INTO registro VALUES (USER, SYSDATE,
USERENV('TERMINAL'));END;/
Para ejecutarlo en SQL*Plus: EXECUTE registrarse;
![Page 7: PL/SQL Francisco Moreno Universidad Nacional. Subprogramas: Procedimientos A excepción de los triggers, hasta ahora los bloques PL/SQL que se han presentado](https://reader033.vdocuments.pub/reader033/viewer/2022061611/5528bde3497959977d8f9d57/html5/thumbnails/7.jpg)
registrarse se puede invocar, por ejemplo, desde un trigger de LOGON así:
CREATE OR REPLACE TRIGGERregistrarAFTER LOGON ON DATABASE BEGINregistrarse; --Llama al procedimientoEND;/Para crear este trigger se requiere:GRANT ADMINISTER DATABASE TRIGGER TO user;
![Page 8: PL/SQL Francisco Moreno Universidad Nacional. Subprogramas: Procedimientos A excepción de los triggers, hasta ahora los bloques PL/SQL que se han presentado](https://reader033.vdocuments.pub/reader033/viewer/2022061611/5528bde3497959977d8f9d57/html5/thumbnails/8.jpg)
Ejemplo 2. Sea la tabla:
DROP TABLE emp;CREATE TABLE emp( cod NUMBER(8) PRIMARY KEY, nom VARCHAR2(15), depto NUMBER(3));INSERT INTO emp VALUES(12,'María',10);INSERT INTO emp VALUES(15,'Ana',5);INSERT INTO emp VALUES(76,'Lisa',15);
![Page 9: PL/SQL Francisco Moreno Universidad Nacional. Subprogramas: Procedimientos A excepción de los triggers, hasta ahora los bloques PL/SQL que se han presentado](https://reader033.vdocuments.pub/reader033/viewer/2022061611/5528bde3497959977d8f9d57/html5/thumbnails/9.jpg)
CREATE OR REPLACE PROCEDURE consulta_emp
(v_nro IN emp.cod%TYPE)ISv_nom emp.nom%TYPE;BEGIN SELECT nom INTO v_nom FROM emp WHERE cod = v_nro; DBMS_OUTPUT.PUT_LINE(v_nom);EXCEPTION WHEN NO_DATA_FOUND THEN DBMS_OUTPUT.PUT_LINE('Empleado no existe');END;/
EXECUTE consulta_emp(15);
Parámetro de entrada
![Page 10: PL/SQL Francisco Moreno Universidad Nacional. Subprogramas: Procedimientos A excepción de los triggers, hasta ahora los bloques PL/SQL que se han presentado](https://reader033.vdocuments.pub/reader033/viewer/2022061611/5528bde3497959977d8f9d57/html5/thumbnails/10.jpg)
Los parámetros de salida usualmente son recibidos por variables de otros subprogramas que los invocan.
CREATE OR REPLACE PROCEDURE consulta_emp(v_nro IN emp.cod%TYPE, v_nom OUT emp.nom
%TYPE)ISBEGIN SELECT nom INTO v_nom -- Se llena el parámetro FROM emp WHERE cod = v_nro; EXCEPTION WHEN NO_DATA_FOUND THEN v_nom := 'Sin nombre'; -- Si no se llena queda en
NULLEND;/
Parámetro de salida
![Page 11: PL/SQL Francisco Moreno Universidad Nacional. Subprogramas: Procedimientos A excepción de los triggers, hasta ahora los bloques PL/SQL que se han presentado](https://reader033.vdocuments.pub/reader033/viewer/2022061611/5528bde3497959977d8f9d57/html5/thumbnails/11.jpg)
Invocación desde otro subprograma:
CREATE OR REPLACE PROCEDURE invoca_consulta(v_nro IN emp.cod%TYPE)IS nombre emp.nom%TYPE;BEGIN consulta_emp(v_nro, nombre); DBMS_OUTPUT.PUT_LINE('El nombre es: ' ||
nombre);END;/
Para ejecutar: EXECUTE invoca_consulta(15);
Retornará con el nombre
Parámetro de salida
![Page 12: PL/SQL Francisco Moreno Universidad Nacional. Subprogramas: Procedimientos A excepción de los triggers, hasta ahora los bloques PL/SQL que se han presentado](https://reader033.vdocuments.pub/reader033/viewer/2022061611/5528bde3497959977d8f9d57/html5/thumbnails/12.jpg)
Ejemplo 3
• Sea el modelo:
MOVIMIENTO
#cons
*valor
CUENTA
#nro
*saldo
de
generadora de
![Page 13: PL/SQL Francisco Moreno Universidad Nacional. Subprogramas: Procedimientos A excepción de los triggers, hasta ahora los bloques PL/SQL que se han presentado](https://reader033.vdocuments.pub/reader033/viewer/2022061611/5528bde3497959977d8f9d57/html5/thumbnails/13.jpg)
Sean las tablas:
CREATE TABLE cuenta(nro NUMBER(8) PRIMARY KEY,saldo NUMBER(8) NOT NULL);
CREATE TABLE mvto(cons NUMBER(8) PRIMARY KEY,valor NUMBER(8) NOT NULL,cta NUMBER(8) NOT NULL REFERENCES cuenta);
![Page 14: PL/SQL Francisco Moreno Universidad Nacional. Subprogramas: Procedimientos A excepción de los triggers, hasta ahora los bloques PL/SQL que se han presentado](https://reader033.vdocuments.pub/reader033/viewer/2022061611/5528bde3497959977d8f9d57/html5/thumbnails/14.jpg)
Ingreso de datos:
INSERT INTO cuenta VALUES(1,100);INSERT INTO cuenta VALUES(2,400);INSERT INTO cuenta VALUES(3,600);
INSERT INTO mvto VALUES(3,20, 2);INSERT INTO mvto VALUES(4,20, 2);INSERT INTO mvto VALUES(5,30, 2);INSERT INTO mvto VALUES(6,20, 2);INSERT INTO mvto VALUES(7,20, 2);INSERT INTO mvto VALUES(8,10, 2);
INSERT INTO mvto VALUES(1,30, 3);INSERT INTO mvto VALUES(2,10, 3);
La cuenta 1 no tiene movimientos
![Page 15: PL/SQL Francisco Moreno Universidad Nacional. Subprogramas: Procedimientos A excepción de los triggers, hasta ahora los bloques PL/SQL que se han presentado](https://reader033.vdocuments.pub/reader033/viewer/2022061611/5528bde3497959977d8f9d57/html5/thumbnails/15.jpg)
Desarrollar un procedimiento que imprima
cada cuenta con sus n valores de
movimiento más altos, en formato horizontal:
Ejemplo: si n = 3, la salida debe ser:
1
2 30 20 20
3 30 10
No tiene movimientos
Solo tiene dos movimientos
Aunque acá se muestran los datos ordenados por nro. de cuenta, por simplicidad no se considerará este aspecto en la solución
![Page 16: PL/SQL Francisco Moreno Universidad Nacional. Subprogramas: Procedimientos A excepción de los triggers, hasta ahora los bloques PL/SQL que se han presentado](https://reader033.vdocuments.pub/reader033/viewer/2022061611/5528bde3497959977d8f9d57/html5/thumbnails/16.jpg)
CREATE OR REPLACE PROCEDURE topn_horizontal(n IN POSITIVE) IScadena VARCHAR2(1000);cont NUMBER(8);BEGIN FOR mi_c1 IN (SELECT nro FROM cuenta) LOOP cadena := mi_c1.nro; cont := 0; FOR mi_c2 IN (SELECT valor FROM mvto WHERE cta = mi_c1.nro ORDER BY 1 DESC) LOOP cadena := cadena || ' ' || mi_c2.valor; cont := cont + 1; EXIT WHEN cont = n; END LOOP; DBMS_OUTPUT.PUT_LINE(cadena); END LOOP;END;/
![Page 17: PL/SQL Francisco Moreno Universidad Nacional. Subprogramas: Procedimientos A excepción de los triggers, hasta ahora los bloques PL/SQL que se han presentado](https://reader033.vdocuments.pub/reader033/viewer/2022061611/5528bde3497959977d8f9d57/html5/thumbnails/17.jpg)
• ¿La solución usando solo SQL?
• La idea es crear una consulta SQL en la que el usuario solo indica el valor de n
• El problema es que en el momento de escribir la consulta no se sabe cuantas columnas se van a necesitar para los top n valores Pero afortunadamente esto se puede solucionar, por ejemplo, con la función de agregación ¡LISTAGG!
![Page 18: PL/SQL Francisco Moreno Universidad Nacional. Subprogramas: Procedimientos A excepción de los triggers, hasta ahora los bloques PL/SQL que se han presentado](https://reader033.vdocuments.pub/reader033/viewer/2022061611/5528bde3497959977d8f9d57/html5/thumbnails/18.jpg)
Pero primero, ¿qué hace la siguiente consulta?
Se usa la función analítica ROW_NUMBER.
CREATE OR REPLACE VIEW v_pos ASSELECT cta, valor, ROW_NUMBER() OVER (PARTITION BY cta ORDER BY valor DESC) AS pos FROM mvto; Nombre para la
columna de salida
Una vista
Para crear vistas se requiere: GRANT CREATE ANY VIEW TO user;
![Page 19: PL/SQL Francisco Moreno Universidad Nacional. Subprogramas: Procedimientos A excepción de los triggers, hasta ahora los bloques PL/SQL que se han presentado](https://reader033.vdocuments.pub/reader033/viewer/2022061611/5528bde3497959977d8f9d57/html5/thumbnails/19.jpg)
• Ahora se muestra un ejemplo con la función LISTAGG ¿qué hace la siguiente consulta?
SELECT cta, LISTAGG(valor,' ') WITHIN GROUP(ORDER BY valor
DESC) AS listadoFROM v_pos GROUP BY cta;
Carácter separador al concatenar los valores, espacio en este ejemplo
![Page 20: PL/SQL Francisco Moreno Universidad Nacional. Subprogramas: Procedimientos A excepción de los triggers, hasta ahora los bloques PL/SQL que se han presentado](https://reader033.vdocuments.pub/reader033/viewer/2022061611/5528bde3497959977d8f9d57/html5/thumbnails/20.jpg)
• Entonces:
SELECT cta || ' ' || LISTAGG(valor, ' ') WITHIN GROUP(ORDER BY valor
DESC) AS listadoFROM v_posWHERE pos <= nGROUP BY cta;
Colocar acá el número deseado
Pero hay un problema: ¡quedan faltando las cuentas que no tienen movimientos!
![Page 21: PL/SQL Francisco Moreno Universidad Nacional. Subprogramas: Procedimientos A excepción de los triggers, hasta ahora los bloques PL/SQL que se han presentado](https://reader033.vdocuments.pub/reader033/viewer/2022061611/5528bde3497959977d8f9d57/html5/thumbnails/21.jpg)
Entonces, una solución en SQL es:
SELECT c1.nro || ' ' || (SELECT LISTAGG(valor, ' ') WITHIN GROUP(ORDER BY valor DESC) FROM v_pos WHERE cta = c1.nro AND pos <= n) AS listadoFROM cuenta c1;
Colocar acá el número deseado
![Page 22: PL/SQL Francisco Moreno Universidad Nacional. Subprogramas: Procedimientos A excepción de los triggers, hasta ahora los bloques PL/SQL que se han presentado](https://reader033.vdocuments.pub/reader033/viewer/2022061611/5528bde3497959977d8f9d57/html5/thumbnails/22.jpg)
• Tarea analizar la siguiente consulta y ver si es equivalente a la anterior solución:
SELECT nro || ' ' || listadoFROM cuenta LEFT OUTER JOIN (SELECT LISTAGG(valor, ' ') WITHIN GROUP(ORDER BY valor DESC) AS listado, cta FROM v_pos WHERE pos <= n GROUP BY cta ) ON (cta = nro);
Colocar acá el número deseado
![Page 23: PL/SQL Francisco Moreno Universidad Nacional. Subprogramas: Procedimientos A excepción de los triggers, hasta ahora los bloques PL/SQL que se han presentado](https://reader033.vdocuments.pub/reader033/viewer/2022061611/5528bde3497959977d8f9d57/html5/thumbnails/23.jpg)
• Sin embargo, dada la cantidad de funciones nuevas que se han incorporado a SQL en las últimas versiones, este empieza a perder su simplicidad y quizás sea preferible una solución vía PL/SQL…
Ejercicio: hacer el mismo problema anterior pero sin considerar valores repetidos, es decir, los n valores de movimiento más altos no repetidos