我正在为大学做这个练习,我已经被困了一个星期。我需要创建一个触发器,以便当表“tbvale”上的状态列发生更改时,相应地会在“tbfuncionario”列上发生一些更新。 我意识到我的代码可能看起来很麻烦甚至不合适,但它是一个旨在教授特定事物的单一练习。 这就是我到目前为止所提出的:
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是tbfuncionario的PK,而fkcodmat是引用pkcodmat的tbvale的FK。
目前我在运行时
UPDATE tbvale SET STATUS = 2 WHERE PKCODVALE = 3;
我收到以下错误:
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
我不明白为什么它会“返回超过请求的行数”,因为只有一行pkcodmat等于fkcodmat。
我很欣赏任何关于为什么会发生这种情况的见解以及我如何解决它。
答案 0 :(得分:2)
触发器看起来相当不错。以下是一些观点:
IF (:NEW.status <> :OLD.status)
不检测更改形式和NULL。而不是身体内的IF
,而是使用触发器WHEN
子句。SELECT valorvale INTO vv FROM tbvale
,这不起作用。您想要一行的值,因此您需要一个WHERE
子句。但是,由于您可能对当前记录值感兴趣,因此您只需使用:new.valorvale
。SELECT fkcodmat INTO cod FROM tbvale
相同。COMMIT
或ROLLBACK
。以下是纠正的触发器:
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;
这是没有变量的相同触发器:
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;
答案 1 :(得分:1)
您不需要导致异常的这些查询:
SELECT valorvale INTO vv FROM tbvale;
SELECT fkcodmat INTO cod FROM tbvale;
假设您希望更新tbvale
行的值,请根据需要使用:old
或:new
记录,例如
vv := :new.valorvalue;
cod := :new.fkcodmat;