首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >“如何在oracle /sql中修复触发器?

“如何在oracle /sql中修复触发器?
EN

Stack Overflow用户
提问于 2019-07-28 00:59:17
回答 2查看 136关注 0票数 1

问题:表A需要一个触发器,用于执行以下操作:每次在表A中对列TRT_PROCEDURE值进行插入时,将1添加到表B中的“TRT_INS_COUNT”列。如果表B中不存在TRT_PROCEDURE值,则将一行添加到表B中,以便将TRT_INS_COUNT设置为1。

每次对表A进行删除时,如果表B中存在该过程值,则将1添加到表B中的表B中的列TRT_DEL_COUNT中,如果表B中不存在该列,则为该过程向表B中添加一行,并将TRT_DEL_COUNT设置为1。

每次对表A中的列TRT_PROCEDURE进行更新时,将1添加到表B中的TRT_UPD_COUNT列中,如果它不在表B中,则将一行添加到表B中的过程值,并将TRT_UPD_COUNT设置为1。如果表A中的列TRT_PROCEDURE值被更改,则为旧的过程值添加1到TRT_UPD_COUNT。

通过执行多个插入、删除和更新来进行测试,然后显示表B。

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

代码语言:javascript
复制
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;
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-07-30 14:49:03

给你,还有几个解决办法。

表:

代码语言:javascript
复制
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)
);

和扳机

代码语言:javascript
复制
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的东西来检测这一点。
  • B没有计数的默认值,所以当原始触发器试图更新表B时,它会将NULL更新为NULL,因为当将1添加到NULL时会发生这种情况。可以通过将0的默认值分配给表中的列,或者使用NVL(trt_upd_count,0) + 1而不是trt_upd_count + 1来解决这个问题。
  • 最后,注意:new:old的用法。看起来它们在这个触发器中是正确的,但它将取决于您的业务情况。
票数 0
EN

Stack Overflow用户

发布于 2019-07-28 03:18:37

在触发器的IF INSERTING部分

代码语言:javascript
复制
UPDATE B
  SET trt_ins_count = trt_ins_count+1
  WHERE :old.trt_procedure = :new.trt_procedure;

当插入新行时,:OLD伪值中的所有值都为空,因此您的更新将永远不会更新任何内容。我想你是说

代码语言:javascript
复制
UPDATE B
  SET trt_ins_count = trt_ins_count+1
  WHERE B.trt_procedure = :new.trt_procedure;

试试看这是否有助于解决你的问题。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/57237194

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档