23
PL/SQL PL/SQL Francisco Moreno Universidad Nacional

PL/SQL Francisco Moreno Universidad Nacional. Subprogramas: Procedimientos A excepción de los triggers, hasta ahora los bloques PL/SQL que se han presentado

Embed Size (px)

Citation preview

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

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

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

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

• 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

• 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

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

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

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

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

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

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

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

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

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

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

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

• ¿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

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

• 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

• 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

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

• 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

• 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