【问题标题】:“How to fix trigger in oracle pl/sql?“如何修复 oracle pl/sql 中的触发器?
【发布时间】:2019-07-28 00:59:17
【问题描述】:

问题: 需要表 A 的触发器,它执行以下操作: 每次在 TRT_PROCEDURE 列的表 A 中插入一个 INSERT 值,加 1 到表 B 中的列“TRT_INS_COUNT”。如果 TRT_PROCEDURE 值确实 B表中不存在,在B表中添加一行,用于程序设置 TRT_INS_COUNT 为 1。

每次对表 A 进行 DELETE 操作时,将表 A 中的 TRT_DEL_COUNT 列加 1 如果该过程值存在于表 B 中,则表 B 为该过程值。如果它不存在 存在于表 B 中,为过程在表 B 中添加一行并设置 TRT_DEL_COUNT 改为 1。

表 A 中的 TRT_PROCEDURE 列每次发生 UPDATE 时,将 1 添加到 表 B 中的 TRT_UPD_COUNT 列。如果不在表 B 中,则添加一行 表 B 的过程值并将 TRT_UPD_COUNT 设置为 1。如果 Column 表 A 中的 TRT_PROCEDURE 值已更改,将 TRT_UPD_COUNT 加 1 旧程序值。

通过执行多次 INSERT、DELETE 和 UPDATE 进行测试,然后显示表 B。

更新:每当将 trt_procedure 的值插入到表 B 中时,第二个相同的 trt_procedure(例如“88-20”)无法正确计入其指定的计数字段。不知道哪里出错了。

TABLE A
Name    Null     Type
TRT_ID  NOT NULL NUMBER(3)
PAT_NBR          NUMBER(4)
PHYS_ID          NUMBER(3)
TRT_PROCEDURE    VARCHAR2(5)
TRT_DATE         DATE


TABLE B
Name          Null     Type
TRT_PROCEDURE NOT NULL VARCHAR2(5)
TRT_INS_COUNT          NUMBER(3)
TRT_DEL_COUNT          NUMBER(3)
TRT_UPD_COUNT          NUMBER(3)

 TEST SAMPLES
  INSERT INTO A VALUES (11, 8031,101,'88-20',sysdate );
  INSERT INTO A VALUES (12, 5872,101,'60-00',sysdate );
  UPDATE A SET trt_procedure = '88-20' WHERE trt_id=6;
   /*row trt_id =6 cloumn trt_procedure old value '54-60'
    new value '88-20', which means Table B row '88-20' and
    row '54-60 both trt_upd_count should add 1*/

  DELETE FROM A WHERE trt_id=1; 
  /*row trt_id =1 cloumn trt_procedure value also '88-20', which means
    that Table B row '88-20' trt_del_count should also add 1*/

CREATE OR REPLACE TRIGGER trt_stats_trg
BEFORE INSERT OR UPDATE OR DELETE OF TRT_procedure ON A FOR EACH ROW
BEGIN
  IF INSERTING THEN
    UPDATE B SET trt_ins_count = trt_ins_count+1
    WHERE B.trt_procedure = :new.trt_procedure;
    IF SQL%NOTFOUND THEN
    INSERT INTO B (trt_procedure, trt_ins_count)
    VALUES (:new.trt_procedure, 1);
    END IF;

 ELSIF UPDATING THEN
   UPDATE B SET trt_upd_count = trt_upd_count+1
   WHERE B.trt_procedure = :old.trt_procedure;
   IF SQL%NOTFOUND THEN
   INSERT INTO B (trt_procedure, trt_upd_count)
   VALUES (:old.trt_procedure, 1);
   END IF;
   UPDATE B SET trt_upd_count = trt_upd_count+1
   WHERE B.trt_procedure = :new.trt_procedure;
   IF SQL%NOTFOUND THEN
   INSERT INTO B (trt_procedure, trt_upd_count)
   VALUES (:new.trt_procedure, 1);
   END IF;

 ELSIF DELETING THEN
   UPDATE B SET trt_del_count = trt_del_count+1
   WHERE B.trt_procedure = :old.trt_procedure;
   IF SQL%NOTFOUND THEN
   INSERT INTO B (trt_procedure, trt_del_count)
   VALUES (:old.trt_procedure, 1);
   END IF;
 END IF;
END trt_stats_trg;

【问题讨论】:

    标签: oracle plsql database-trigger


    【解决方案1】:

    这里有一些修复。

    表格:

    create table a(
      TRT_ID  NUMBER(3) NOT NULL ,
      PAT_NBR          NUMBER(4),
      PHYS_ID          NUMBER(3),
      TRT_PROCEDURE    VARCHAR2(5),
      TRT_DATE         DATE
    );
    create table b(
      TRT_PROCEDURE VARCHAR2(5) NOT NULL,
      TRT_INS_COUNT          NUMBER(3),
      TRT_DEL_COUNT          NUMBER(3),
      TRT_UPD_COUNT          NUMBER(3)
    );
    

    还有触发器

    CREATE OR REPLACE TRIGGER trt_stats_trg
    BEFORE INSERT OR UPDATE OR DELETE ON A FOR EACH ROW
    BEGIN
      IF INSERTING THEN
        UPDATE B SET trt_ins_count = nvl(trt_ins_count,0)+1
          WHERE B.trt_procedure = :new.trt_procedure;
        IF SQL%NOTFOUND THEN
          INSERT INTO B (trt_procedure, trt_ins_count)
          VALUES (:new.trt_procedure, 1);
        END IF;
    
     ELSIF UPDATING('TRT_PROCEDURE') THEN
       if nvl(:old.trt_procedure, 'X') <> nvl(:new.trt_procedure, 'X') then
         UPDATE B SET trt_upd_count = nvl(trt_upd_count,0)+1
           WHERE B.trt_procedure = :old.trt_procedure;
         IF SQL%NOTFOUND THEN
           INSERT INTO B (trt_procedure, trt_upd_count)
           VALUES (:old.trt_procedure, 1);
         END IF;
         UPDATE B SET trt_upd_count = nvl(trt_upd_count,0)+1
           WHERE B.trt_procedure = :new.trt_procedure;
         IF SQL%NOTFOUND THEN
           INSERT INTO B (trt_procedure, trt_upd_count)
           VALUES (:new.trt_procedure, 1);
         END IF;
       end if;
     ELSIF DELETING THEN
       UPDATE B SET trt_del_count = nvl(trt_del_count, 0)+1
       WHERE B.trt_procedure = :old.trt_procedure;
       IF SQL%NOTFOUND THEN
         INSERT INTO B (trt_procedure, trt_del_count)
         VALUES (:old.trt_procedure, 1);
       END IF;
     END IF;
    END trt_stats_trg;
    /
    

    关键点:

    • 您可以使用UPDATING('COLUMN_NAME') 来检测SQL 何时影响特定列。

    • UPDATING 时,您可能希望检查未更改的更新,其中值为“ABC”的列正在更新为“ABC”。这通常发生在仅将所有列包含在更新中的框架中,即使它们并没有真正改变。使用类似于if nvl(:old.trt_procedure, 'X') &lt;&gt; nvl(:new.trt_procedure, 'X') then 的内容检测。

    • 1234563当您将 1 添加到 NULL 时会发生这种情况。这可以通过为表中的列分配默认值0 或使用NVL(trt_upd_count,0) + 1 而不是trt_upd_count + 1 来解决。
    • 最后,注意:new:old 的用法。看起来它们在此触发器中是正确的,但这取决于您的业务案例。

    【讨论】:

      【解决方案2】:

      在您的触发器的IF INSERTING 部分中,您有

      UPDATE B
        SET trt_ins_count = trt_ins_count+1
        WHERE :old.trt_procedure = :new.trt_procedure;
      

      在插入新行时,:OLD 伪行中的所有值都是 NULL,因此您的 UPDATE 将永远不会更新任何内容。我想你的意思是

      UPDATE B
        SET trt_ins_count = trt_ins_count+1
        WHERE B.trt_procedure = :new.trt_procedure;
      

      尝试一下,看看这是否有助于解决您的问题。

      【讨论】:

      • 谢谢,IF UPDATING 部分是问题所在。
      • 我这样编辑它,但它并没有正确计算更新的 TRT_PROCEDURE。
      • IF UPDATING THEN UPDATE B SET trt_upd_count = trt_upd_count+1 WHERE B.trt_procedure = :old.trt_procedure; IF SQL%NOTFOUND THEN INSERT INTO B (trt_procedure, trt_upd_count) VALUES (:old.trt_procedure, 1); END IF; UPDATE B SET trt_upd_count = trt_upd_count+1 WHERE B.trt_procedure = :new.trt_procedure; IF SQL%NOTFOUND THEN INSERT INTO B (trt_procedure, trt_upd_count) VALUES (:new.trt_procedure, 1); END IF; END IF;
      • 每当表 A 中除 trt_procedure 之外的列被更新但 trt_procedure 未更新时,您的更新过程都会双倍计数。你增加 for :old.trt_procedure 和 for :new_trt_procedure 即使它们相同。
      • 我按照建议修改了触发器。感谢您的提示,不幸的是问题仍然存在。修改后的代码如上。
      猜你喜欢
      • 1970-01-01
      • 2011-07-29
      • 1970-01-01
      • 2020-12-23
      • 2014-04-07
      • 2017-09-08
      • 1970-01-01
      • 1970-01-01
      • 2021-03-28
      相关资源
      最近更新 更多