I'm doing this exercise for university and I've been stuck for a week. I need to create a trigger so that when the status column on table "tbvale" is changed a few updates happen on column "tbfuncionario" accordingly. I realize my code probably looks cumbersome and even inappropriate perhaps but it's an uni exercise designed to teach specific things. That's what I came up with so far:
CREATE OR REPLACE TRIGGER status_chg
AFTER UPDATE OF status ON tbvale
FOR EACH ROW
DECLARE
nvd tbfuncionario.numvalesdescontados%type;
nva tbfuncionario.numvalesaberto%type;
vtva tbfuncionario.valortotalvalesaberto%type;
nve tbfuncionario.numvalesemitidos%type;
vv tbvale.valorvale%type;
cod tbvale.fkcodmat%type;
pragma autonomous_transaction;
BEGIN
IF (:NEW.status <> :OLD.status) THEN
SELECT valorvale INTO vv FROM tbvale;
SELECT fkcodmat INTO cod FROM tbvale;
IF (:NEW.status = 2) THEN
nvd := 1;
nva := -1;
nve := 0;
vv := vv - 1;
ELSE
nvd := 0;
nve := 1;
nva := 1;
vv := vv + 1;
END IF;
UPDATE tbfuncionario
SET numvalesdescontados = numvalesdescontados + nvd,
numvalesaberto = numvalesaberto + nva,
numvalesemitidos = numvalesemitidos + nve,
valortotalvalesaberto = valortotalvalesaberto + vv
WHERE pkcodmat = cod;
END IF;
END;
pkcodmat is the PK of tbfuncionario and fkcodmat is the FK of tbvale referencing pkcodmat.
Currently when I run
UPDATE tbvale SET STATUS = 2 WHERE PKCODVALE = 3;
I get the following error:
ERROR: ORA-01422: exact fetch returns more than requested
number of rows ORA-06512: at "ULBRA.STATUS_CHG", line 11
ORA-04088: error during execution of trigger 'ULBRA.STATUS_CHG'
Error Code: 1422
Query = UPDATE tbvale SET STATUS = 2 WHERE PKCODVALE = 3
I don't understand why it would "return more than requested number of rows" as there is only one row where pkcodmat is equal to fkcodmat.
I appreciate any insights as to why that is happening and how I could fix it.
The trigger look quite good. Here are some points:
IF (:NEW.status <> :OLD.status)
doesn't detect changes form and to NULL, in case the column is nullable. Rather than IF
inside the body, I'd use the triggers WHEN
clause instead. SELECT valorvale INTO vv FROM tbvale
, This doesn't work. You want the value of one row, so you'd need a WHERE
clause. But as you are supposedly interested in the current records value, you can simply use :new.valorvale
. SELECT fkcodmat INTO cod FROM tbvale
. COMMIT
or ROLLBACK
at the end. Here is the trigger corrected:
CREATE OR REPLACE TRIGGER status_chg
AFTER UPDATE OF status ON tbvale
FOR EACH ROW
WHEN (DECODE(NEW.STATUS, OLD.STATUS, 0, 1) = 1)
DECLARE
v_vd integer;
v_va integer;
v_ve integer;
v_vv tbvale.valorvale%type;
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
IF (:NEW.status = 2) THEN
v_vd := 1;
v_va := -1;
v_ve := 0;
v_vv := :NEW.valorvale - 1;
ELSE
v_vd := 0;
v_va := 1;
v_ve := 1;
v_vv := :NEW.valorvale + 1;
END IF;
UPDATE tbfuncionario
SET numvalesdescontados = numvalesdescontados + v_vd,
numvalesaberto = numvalesaberto + v_va,
numvalesemitidos = numvalesemitidos + v_ve,
valortotalvalesaberto = valortotalvalesaberto + v_vv
WHERE pkcodmat = :NEW.fkcodmat;
COMMIT;
END;
And here is the same trigger without variables:
CREATE OR REPLACE TRIGGER status_chg
AFTER UPDATE OF status ON tbvale
FOR EACH ROW
WHEN (DECODE(NEW.STATUS, OLD.STATUS, 0, 1) = 1)
DECLARE
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
UPDATE tbfuncionario
SET numvalesdescontados = numvalesdescontados + CASE WHEN :NEW.status = 2 THEN 1 ELSE 0 END
, numvalesaberto = numvalesaberto + CASE WHEN :NEW.status = 2 THEN -1 ELSE 1 END
, numvalesemitidos = numvalesemitidos + CASE WHEN :NEW.status = 2 THEN 0 ELSE 1 END
, valortotalvalesaberto = valortotalvalesaberto + :NEW.valorvale + CASE WHEN :NEW.status = 2 THEN -1 ELSE 1 END
WHERE pkcodmat = :NEW.fkcodmat;
COMMIT;
END;
You don't need these queries which are causing the exception:
SELECT valorvale INTO vv FROM tbvale;
SELECT fkcodmat INTO cod FROM tbvale;
Assuming you want the values from the tbvale
row being updated, use the :old
or :new
record as appropriate eg
vv := :new.valorvalue;
cod := :new.fkcodmat;
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.