“如何修复 oracle pl/sql 中的触发器?

“How to fix trigger in oracle pl/sql?

问题: Table A 需要一个 TRIGGER,它执行以下操作: 每次INSERT在TRT_PROCEDURE列的值上做成TableA,加1 到 table B 中的 'TRT_INS_COUNT' 列。如果 TRT_PROCEDURE 值不 table B 中不存在,在table B 中添加一行用于程序设置 TRT_INS_COUNT 到 1.

每次对 Table A 进行 DELETE 时,将 1 添加到列 TRT_DEL_COUNT table B 用于该过程值,如果它存在于 table B 中。如果它不存在 存在于table B中,在table B中添加一行用于程序并设置 TRT_DEL_COUNT 到 1.

每次对 TABLE A 中的列 TRT_PROCEDURE 进行更新时,将 1 添加到 column TRT_UPD_COUNT in table B. 如果它不在 table B 中,添加一行到 table B 作为过程值并将 TRT_UPD_COUNT 设置为 1。如果列 TRT_PROCEDURE中的值TABLEA被改变,为TRT_UPD_COUNT加1 旧程序值。

通过多次插入、删除和更新进行测试,然后显示 table B。

更新:每当将 trt_procedure 的值插入 table 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;

在你的触发器的 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;

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

给你,有一些修复。

tables:

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') <> nvl(:new.trt_procedure, 'X') then.

  • 的内容检测此问题
  • Table B 没有计数的默认值,所以当原始触发器尝试更新 table B 时,它成功了...将 NULL 更新为 NULL,因为这就是将 1 添加到 NULL 时发生的情况。这可以通过为 table 中的列分配默认值 0 或使用 NVL(trt_upd_count,0) + 1 而不是 trt_upd_count + 1.

    [=44 来解决=]
  • 最后,注意 :new:old 的用法。看起来他们在此触发器中是正确的,但这将取决于您的业务案例。