簡體   English   中英

Oracle PL / SQL觸發器可更新其他表

[英]Oracle PL/SQL trigger that updates a different table

我正在大學里做這個練習,已經被困了一個星期。 我需要創建一個觸發器,以便在更改表“ 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是tbvale引用pkcodmat的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。

我感謝任何關於為什么會發生這種情況以及如何解決它的見解。

觸發器看起來還不錯。 以下是一些要點:

  1. IF (:NEW.status <> :OLD.status)IF (:NEW.status <> :OLD.status)可為空的情況下,不會檢測到形式更改為NULL。 我將使用觸發器WHEN子句,而不是在主體內部使用IF
  2. 您正在使用列類型作為變量。 但是,這些只能容納整數。 因此,不需要列類型。
  3. SELECT valorvale INTO vv FROM tbvale ,這不起作用。 您需要一行的值,因此需要一個WHERE子句。 但是,由於您可能對當前記錄的值感興趣,因此可以簡單地使用:new.valorvale
  4. SELECT fkcodmat INTO cod FROM tbvaleSELECT fkcodmat INTO cod FROM tbvale
  5. 自治觸發器最后需要COMMITROLLBACK

這是已更正的觸發器:

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;

您不需要引起異常的這些查詢:

SELECT valorvale INTO vv FROM tbvale;
SELECT fkcodmat INTO cod FROM tbvale;

假設您希望更新tbvale行中的值,請根據tbvale使用:old:new記錄,例如

vv := :new.valorvalue;
cod := :new.fkcodmat;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM