PL/SQL Procedures, Functions, and Triggers

PL/SQL Procedure EJ1

This PL/SQL procedure inserts data into the PERMISOS table based on data from the USUARIOS table.

CREATE OR REPLACE PROCEDURE EJ1(
    p_ciudad usuarios.ciudad%TYPE,
    p_dpto usuarios.dpto%TYPE,
    p_total OUT number
) AS
    CURSOR c_usuarios IS
        SELECT idu, dpto
        FROM usuarios
        WHERE dpto = p_dpto AND ciudad = p_ciudad;
BEGIN
    p_total := 0;
    FOR v_registro IN c_usuarios LOOP
        INSERT INTO PERMISOS VALUES (v_registro.idu, p_dpto, 'DELETE', 'MITABLA');
        p_total := p_total + 1;
    END LOOP;
EXCEPTION
    WHEN OTHERS THEN
        DBMS_OUTPUT.PUT_LINE('An error occurred: ' || SQLCODE || ' message: ' || SQLERRM);
END;

Example Usage of Procedure EJ1

DECLARE
    v_dpto usuarios.dpto%TYPE;
    v_ciudad usuarios.ciudad%TYPE;
    v_total number;
BEGIN
    v_dpto := 'INF';
    v_ciudad := 'Murcia';
    EJ1(v_ciudad, v_dpto, v_total);
    DBMS_OUTPUT.PUT_LINE('The total number of users requested is: ' || v_total);
END;

PL/SQL Function EJ2

This PL/SQL function returns the total number of rows in PERMISOS with tipo ‘DELETE’ for a given department (p_dpto).

CREATE OR REPLACE FUNCTION EJ2 (
    p_idu usuarios.idu%TYPE,
    p_dpto usuarios.dpto%TYPE
)
RETURN number IS
    totalTablas NUMBER(5) := 0;
    contador NUMBER(3) := 0;
BEGIN
    SELECT COUNT(*) INTO contador FROM usuarios WHERE dpto = p_dpto;
    IF contador = 0 THEN
        RAISE_APPLICATION_ERROR(-20001, 'User does not exist.');
    END IF;

    SELECT COUNT(*) INTO totalTablas FROM PERMISOS WHERE dpto = p_dpto AND tipo = 'DELETE';
    RETURN totalTablas;
EXCEPTION
    WHEN OTHERS THEN
      DBMS_OUTPUT.PUT_LINE('An error occurred.');
END;

PL/SQL Trigger EJ3

This PL/SQL trigger logs operations on the PERMISOS table and executes a revoke command.

CREATE OR REPLACE TRIGGER EJ3
BEFORE INSERT OR UPDATE OR DELETE ON PERMISOS
FOR EACH ROW
DECLARE
    CAD VARCHAR2(200);
BEGIN
    IF INSERTING OR UPDATING THEN
        INSERT INTO LOGS VALUES (:OLD.IDU, :OLD.TIPO, :OLD.DPTO, :OLD.TABLA, SYSDATE);
        CAD := 'REVOKE ' || :OLD.TIPO || ' ON ' || :OLD.TABLA || ' FROM ' || :OLD.IDU;
        EXECUTE IMMEDIATE CAD;
    END IF;
EXCEPTION
    WHEN OTHERS THEN
        NULL; -- Consider better error handling
END;

PL/SQL Function EJ4

Calculates the total amount of orders for a specific product and store.

CREATE OR REPLACE FUNCTION EJ4 (
    v_tid pedidos.tid%TYPE,
    v_pid pedidos.pid%TYPE
) RETURN NUMBER AS
    total_ped NUMBER := 0;
BEGIN
    SELECT SUM(cant * precio) INTO total_ped
    FROM pedidos, productos
    WHERE v_tid = pedidos.tid AND v_pid = pedidos.pid AND pedidos.pid = productos.pid;
    RETURN total_ped;
    -- DBMS_OUTPUT.PUT_LINE is not allowed inside a function used in SQL.
END EJ4;

PL/SQL Procedure StockCorrecto

Checks and updates product stock.

CREATE OR REPLACE PROCEDURE StockCorrecto (
    p_pid pedidos.pid%TYPE,
    correcto OUT VARCHAR2(2)
) IS
    stockActual productos.stock%TYPE;
    stockCorrecto productos.stock%TYPE;
    totalPedido pedidos.cant%TYPE;
BEGIN
    SELECT stock INTO stockActual FROM productos WHERE pid = p_pid;
    SELECT SUM(cant) INTO totalPedido FROM pedidos WHERE pid = p_pid;
    stockCorrecto := 1000 - totalPedido;
    IF stockCorrecto < 0 THEN
        correcto := 'uf';
        UPDATE productos SET stock = 0;
    ELSIF stockActual = stockCorrecto THEN
        correcto := 'ok'; -- Added missing assignment
    ELSIF stockActual <> stockCorrecto THEN
        correcto := 'nk';
    END IF;
END;

Example Usage:

DECLARE
  idPr productos.pid%TYPE;
  v_correcto VARCHAR2(2); -- Corrected variable name
BEGIN
  idPr := 3;
  StockCorrecto(idPr, v_correcto); -- Corrected variable name
  DBMS_OUTPUT.PUT_LINE(v_correcto);
END;

PL/SQL Trigger stockActualizado

This trigger updates the stock in the productos table when a new order is inserted, updated, or deleted in the pedidos table.

CREATE OR REPLACE TRIGGER stockActualizado
BEFORE INSERT OR UPDATE OR DELETE ON pedidos
FOR EACH ROW
DECLARE
    stockActual productos.stock%TYPE;
BEGIN
    IF INSERTING THEN
        SELECT stock INTO stockActual FROM productos WHERE pid = :NEW.PID;
        IF (stockActual - (:NEW.CANT)) < 0 THEN
            RAISE_APPLICATION_ERROR(-20001, 'Stock cannot be negative.');
        ELSE
            UPDATE productos SET stock = stock - :NEW.cant WHERE pid = :NEW.pid;
        END IF;
    END IF;

    IF UPDATING THEN -- Added missing update logic
        SELECT stock INTO stockActual FROM productos WHERE pid = :NEW.PID;
        IF (stockActual - (:NEW.CANT - :OLD.CANT)) < 0 THEN
            RAISE_APPLICATION_ERROR(-20001, 'Stock cannot be negative.');
        ELSE
            UPDATE productos SET stock = stock - (:NEW.cant - :OLD.cant) WHERE pid = :NEW.pid;
        END IF;
    END IF;

    IF DELETING THEN
        UPDATE PRODUCTOS SET stock = stock + (:OLD.cant) WHERE pid = :OLD.pid;
    END IF;
EXCEPTION
    WHEN OTHERS THEN
        DBMS_OUTPUT.PUT_LINE('An error occurred...');
END;

PL/SQL Anonymous Block (Cursor Example)

Calculates the total weight of orders from Barcelona with a price greater than 50.

DECLARE
    CURSOR pedBarcelona IS
        SELECT p.cant, pr.peso
        FROM pedidos p, productos pr, almacenes a
        WHERE p.pid = pr.pid AND p.aid = a.aid AND a.aloc = 'Barcelona' AND pr.precio > 50;
    total NUMBER(15, 2) := 0;
BEGIN
    FOR v IN pedBarcelona LOOP
        total := total + (v.cant * v.peso);
    END LOOP;
    DBMS_OUTPUT.PUT_LINE('The total is ' || total);
END;