Práctica final PL/SQL 12c
1. Objetivos
Esta práctica pretende hacer un repaso de los componentes más importantes de
PL/SQL: procedimintos, funciones, paquetes y triggers.
2. Crear las tablas y datos necesarios
Vamos a crear cuatro tablas. Podemos ejecutar el script “creación_ddl.sql” que
se encuentra en los recursos del capítulo o bien podéis copiarlo y pegarlo de este
documento
FACTURAS
LINEAS_FACTURA
LOG_CONTROL
PRODUCTOS
Las columnas de cada tabla con la siguientes:
FACTURAS
COD_FACTURA NUMBER
FECHA DATE
DESCRIPCIÓN VARCHAR2(100)
Clave primaria: COD_FACTURA
LINEAS_FACTURAS
COD_PRODUCTO NUMBER
COD_FACTURA NUMBER
PVP NUMBER
UNIDADES NUMBER
FECHA DATE
Clave Primaria: COD_FACTURA+COD_PRODUCTO
Referencia a la tabla FACTURAS y a la tabla PRODUCTOS
ALTER TABLE "HR"."LINEAS_FACTURA" MODIFY ("COD_PRODUCTO"
NOT NULL ENABLE);
ALTER TABLE "HR"."LINEAS_FACTURA" MODIFY ("COD_FACTURA"
NOT NULL ENABLE);
REM INSERTING into HR.PRODUCTOS
SET DEFINE OFF;
Insert into HR.PRODUCTOS
(COD_PRODUCTO,NOMBRE_PRODUCTO,PVP,TOTAL_VENDIDOS) values
('1','TORNILLO','1',null);
Insert into HR.PRODUCTOS
(COD_PRODUCTO,NOMBRE_PRODUCTO,PVP,TOTAL_VENDIDOS) values
('2','TUERCA','5',null);
Insert into HR.PRODUCTOS
(COD_PRODUCTO,NOMBRE_PRODUCTO,PVP,TOTAL_VENDIDOS) values
('3','ARANDELA','4',null);
Insert into HR.PRODUCTOS
(COD_PRODUCTO,NOMBRE_PRODUCTO,PVP,TOTAL_VENDIDOS) values
('4','MARTILLO','40',null);
Insert into HR.PRODUCTOS
(COD_PRODUCTO,NOMBRE_PRODUCTO,PVP,TOTAL_VENDIDOS) values
('5','CLAVO','1',null);
3. Componentes de la práctica
La práctica pretende realizar los componentes necesarios para gestionar esas
tablas. En concreto:
o Paquete para gestionar las facturas
o Paquete para gestionar las líneas de factura
o Triggers para controlar el acceso a las tablas
o
PAQUETE FACTURAS
PROCEDIMIENTOS
ALTA_FACTURA (COD_FACTURA, FECHA,DESCRIPCIÓN).
o Debe dar de alta una factura con los valores indicados en los
parámetros
o Debe comprobar que no se duplica
BAJA_FACTURA (cod_factura).
o Debe borrar la factura indicada en el parámetros
o Debe borrar también las líneas de facturas asociadas en la tabla
LINEAS_FACTURA.
MOD_DESCRI(COD_FACTURA, DESCRIPCION).
o Debe modificar la descripción de la factura que tenga el código del
parámetro con la nueva descripción
MOD_FECHA (COD_FACTURA,FECHA).
o Debe modificar la descripción de la factura que tenga el código del
parámetro con la nueva fecha
o
FUNCIONES
NUM_FACTURAS(FECHA_INICIO,FECHA_FIN).
o Devuelve el número de facturas que hay entre esas fechas
TOTAL_FACTURA(COD_FACTURA.)
o Devuelve el total de la factura con ese código. Debe consultar el
campo TOTAL_VENTAS de la tabla LINEAS_FACTURA
PAQUETE LINEA_FACTURAS
PROCEDIMIENTOS
ALTA_LINEA (COD_FACTURA, COD_PRODUCTO, UNIDADES,
FECHA)
o Procedimiento para insertar una línea de Factura
o Debe comprobar que existe ya la factura antes de insertar el registro.
o También debemos comprobar que existe el producto en la tabla de
PRODUCTOS.
o El PVP debemos seleccionarlo de la tabla PRODUCTOS
BAJA_LINEA (cod_factura, COD_PRODUCTO
o Damos de baja la línea con esa clave primaria)
MOD_PRODUCTO(COD_FACTURA,COD_PRODUCTO,PARAMETRO)
o Se trata de 2 métodos sobrecargados, es decir el segundo parámetro
debe admitir los siguientes valores:
MOD_PRODUCTO(COD_FACTURA,COD_PRODUCTO,
UNIDADES)
MOD_PRODUCTO(COD_FACTURA,COD_PRODUCTO,
FECHA)
o Por tanto, debe modificar o bien unidades si se le pasa un NUMBER
o bien la fecha si se le pasa un DATE
FUNCIONES
NUM_LINEAS(COD_FACTURA)
o Devuelve el número de líneas de la factura
TRIGGERS
Triggers de tipo sentencia
Creamos 2 triggers de tipo SENTENCIA, uno para la tabla FACTURAS y
otro para la tabla LINEAS_FACTURA
Cada cambio en alguna de las tablas (Insert, update, delete), debe generar
una entrada en la tabla CONTROL_LOG con los datos siguientes:
o Tabla (FACTURAS O LONEAS_FACTURA)
o Fecha usamos la función SYSDATE
o Usuario que lo ha realizado función USER
o Operación realizada (I-U-D)
Trigger de tipo fila
La columna TOTAL_VENDIDO, de la tabla PRODUCTOS mantiene el
total de ventas de un determinado producto.
Prac controlaro, creamos un Trigger de tipo fila sobre la tabla
LINEAS_FACTURA, de forma que cada vez que se añada, cambie o borre
una línea se actualice en la tabla PRODUCTOS la columna
TOTAL_VENDIDO.
Si se inserta una nueva línea con ese producto, se debe añadir el total al
campo.
Si se borra la línea debemos restar el total
Si se modifica, debemos comprobar si el valor antiguo era superior al nuevo
y sumamos o restamos dependiendo del resultado
SOLUCIONES A LA PRÁCTICA FINAL
Páquete FACTURAS
create or replace PACKAGE FACTURASP AS
PROCEDURE ALTA_FACTURA (CODIGO NUMBER, FECHA DATE,
DESCRIP VARCHAR2);
PROCEDURE BAJA_FACTURA (CODIGO NUMBER);
PROCEDURE MOD_DESCRI(CODIGO NUMBER,DESCRI VARCHAR2);
PROCEDURE MOD_FECHA(CODIGO NUMBER, FECHA_MOD DATE);
FUNCTION NUM_FACTURAS (FECHA_INICIO DATE,FECHA_FIN DATE)
RETURN NUMBER;
FUNCTION TOTAL_FACTURA(CODIGO NUMBER) RETURN NUMBER;
END FACTURASp;
/
create or replace PACKAGE BODY facturasp AS
--FUNCIÓN ADICIONAL PARA COMPROBAR SI EXISTE UNA FACTURA, Se
trata de una función PRIVADA
FUNCTION existe (
codigo NUMBER
) RETURN BOOLEAN IS
cont NUMBER := 0;
cod_f facturas.cod_factura%type;
BEGIN
--Comprobar si existe la factura:
SELECT
cod_factura into cod_f FROM facturas
where cod_factura=codigo;
RETURN true;
EXCEPTION
WHEN NO_DATA_FOUND THEN
return false;
WHEN OTHERS THEN
RAISE_APPLICATION_ERROR(-20000,'ERROR'|| sqlcode);
END;
--PROCEDURE ALTA_FACTURA
PROCEDURE alta_factura (
codigo NUMBER,
fecha DATE,
descrip VARCHAR2
) AS
devuelto BOOLEAN;
erroryaexiste EXCEPTION;
BEGIN
devuelto := existe(codigo);
IF not devuelto THEN
INSERT INTO facturas VALUES (codigo,fecha, descrip );
commit;
ELSE
RAISE erroryaexiste;
END IF;
EXCEPTION
WHEN erroryaexiste THEN
RAISE_APPLICATION_ERROR(-20001,'ERROR, ESE NÚMERO DE
FACTURA YA EXISTE, NO SE ADMITEN DUPLICADOS');
WHEN OTHERS THEN
RAISE_APPLICATION_ERROR(-20000,'ERROR'|| sqlcode);
END;
--PROCEDURE BAJA_FACTURA.
PROCEDURE baja_factura (
codigo NUMBER
) AS
errornoexiste EXCEPTION;
devuelto BOOLEAN;
BEGIN
END lineas_facturasp;
Triggers
--TRIGGER PARA CONTROLAR LA TABLA FACTURAS
create or replace TRIGGER T_FACTURAS
BEFORE DELETE OR INSERT OR UPDATE ON FACTURAS
DECLARE
OPERACION CHAR(1);
BEGIN
IF INSERTING THEN
OPERACION:='I';
END IF;
IF UPDATING THEN
OPERACION:='U';
END IF;
IF DELETING THEN
OPERACION:='D';
END IF;
INSERT INTO CONTROL_LOG VALUES
(USER,SYSDATE,'FACTURAS',OPERACION);
END;
--TRIGGER PARA CONTROLAR LA TABLA LINEAS_FACTURA
create or replace TRIGGER T_LINEAS_FACTURAS
BEFORE DELETE OR INSERT OR UPDATE ON LINEAS_FACTURA
DECLARE
OPERACION CHAR(1);
BEGIN
IF INSERTING THEN
OPERACION:='I';
END IF;
IF UPDATING THEN
OPERACION:='U';
END IF;
IF DELETING THEN
OPERACION:='D';
END IF;
INSERT INTO CONTROL_LOG VALUES
(USER,SYSDATE,'LINEAS_FACTURA',OPERACION);
END;
/
--TRIGGER PARA CONTROLAR LA COLUMNA TOTAL_VENDIDOS DE LA
TABLA PRODUCTOS
create or replace TRIGGER T_LINEAS_FACTURAS_PRECIO
AFTER DELETE OR INSERT OR UPDATE ON LINEAS_FACTURA
FOR EACH ROW
DECLARE
--- VARIABLE PARA CONTROLA REL UPDATE
TOTAL_CAMBIO NUMBER:=0;
BEGIN
IF INSERTING THEN
UPDATE PRODUCTOS SET
TOTAL_VENDIDOS=TOTAL_VENDIDOS+(:NEW.PVP*:NEW.UNIDADES)
WHERE COD_PRODUCTO=:NEW.COD_PRODUCTO;
END IF;
IF UPDATING THEN
TOTAL_CAMBIO:=(:OLD.PVP*:OLD.UNIDADES)-
(:NEW.PVP*:NEW.UNIDADES);
UPDATE PRODUCTOS SET
TOTAL_VENDIDOS=TOTAL_VENDIDOS+TOTAL_CAMBIO
WHERE COD_PRODUCTO=:NEW.COD_PRODUCTO;
END IF;
IF DELETING THEN
UPDATE PRODUCTOS SET TOTAL_VENDIDOS=TOTAL_VENDIDOS-
(:NEW.PVP*:NEW.UNIDADES)