[英]Oracle PL/SQL trigger that updates a different table
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.
我需要创建一个触发器,以便在更改表“ tbvale”上的状态列时,相应地在列“ tbfuncionario”上进行一些更新。 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. pkcodmat是tbfuncionario的PK,fkcodmat是tbvale引用pkcodmat的FK。
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. 我不明白为什么它会“返回超过请求的行数”,因为只有一行pkcodmat等于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. IF (:NEW.status <> :OLD.status)
在IF (:NEW.status <> :OLD.status)
可为空的情况下,不会检测到形式更改为NULL。 Rather than IF
inside the body, I'd use the triggers WHEN
clause instead. WHEN
子句,而不是在主体内部使用IF
。 SELECT valorvale INTO vv FROM tbvale
, This doesn't work. SELECT valorvale INTO vv FROM tbvale
,这不起作用。 You want the value of one row, so you'd need a WHERE
clause. WHERE
子句。 But as you are supposedly interested in the current records value, you can simply use :new.valorvale
. :new.valorvale
。 SELECT fkcodmat INTO cod FROM tbvale
. SELECT fkcodmat INTO cod FROM tbvale
为SELECT fkcodmat INTO cod FROM tbvale
。 COMMIT
or ROLLBACK
at the end. COMMIT
或ROLLBACK
。 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 假设您希望更新
tbvale
行中的值,请根据tbvale
使用:old
或:new
记录,例如
vv := :new.valorvalue;
cod := :new.fkcodmat;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.