【问题标题】:Update Trigger is updating multiple records instead of single record更新触发器正在更新多条记录而不是单条记录
【发布时间】:2021-10-16 10:24:21
【问题描述】:

我是触发器的新手,在更新触发器期间遇到问题。 设想: 我有两个表 [table1 和 table2] 当 table1 中的特定列发生变化时,我需要根据几个条件更新 table2 记录

这是我的触发器,

create or replace TRIGGER UPDATE_TABLE1 
BEFORE UPDATE OF LOWTHRESHOLD, HIGHTHRESHOLD ON TABLE1 
for each row
  when(nvl(old.LOWTHRESHOLD,0) <> nvl(new.LOWTHRESHOLD,0) 
  OR  nvl(old.HIGHTHRESHOLD,0) <> nvl(new.HIGHTHRESHOLD,0))
  declare
  PID number(3) := nvl(:old.PID,0);
  oldLOWTH number(2) := nvl(:old.LOWTHRESHOLD,0);
  oldHIGHTH number(2) := nvl(:old.HIGHTHRESHOLD,0);
  newLOWTH number(2) := nvl(:new.LOWTHRESHOLD,0);
  newHIGHTH number(2) := nvl(:new.HIGHTHRESHOLD,0);
  ratio DOUBLE PRECISION;
  oldTHCrossed number(1) := 0;
  objID number(10) := 0;
  objType number(1) := 0;
   CURSOR profileUtil_Cursor  IS
        SELECT * FROM TABLE2 where upid = PID; 
  begin
    
  dbms_output.enable(1000);
 
  FOR v_record in profileUtil_Cursor LOOP
  ratio := v_record.UTILIZATIONRATIO;
  oldTHCrossed := v_record.THCROSSED;
  objID := v_record.objID;
  objType := v_record.objType;
 IF(ratio < newLOWTH AND ratio < newHIGHTH ) THEN
  UPDATE TABLE2 SET THCROSSED = 1, LASTUPDATED = date_to_miniseconds(sysdate) 
  WHERE objID = objID and objType = objType and upid = PID;
  ELSIF(newLOWTH <= ratio AND ratio <= newHIGHTH) THEN 
    UPDATE TABLE2 SET THCROSSED = 2, LASTUPDATED = date_to_miniseconds(sysdate) 
    WHERE objID = objID and objType = objType and upid = PID; 
  ELSIF(ratio > newHIGHTH) THEN
    UPDATE TABLE2 SET THCROSSED = 3, LASTUPDATED = date_to_miniseconds(sysdate)
    WHERE upid = PID and objID = objID and objType = objType; 
  END IF;
  END LOOP;
    IF SQL%NOTFOUND THEN
        DBMS_OUTPUT.put_line('NOT FOUND');
    END IF;
END;

但是当这个触发器被执行时,TABLE2 中的所有记录都被更新了。 请提供一些解决此问题的建议。

【问题讨论】:

  • 不要使用与列名相同的变量名。因为那时您无法分辨什么是变量,什么是表列。目前我可以假设WHERE objID = objID and objType = objType 是常量,除非某些列具有null 值。除上述问题外,您还可以使用merge 语句和case 表达式计算THCROSSED 来更新目标表,无需命令逻辑。
  • 看起来这三个更新除了thcrossed的值是一样的。我会将其作为变量,根据您的逻辑将其设置为 1、2 或 3,然后进行一次更新。此外,稍微小心地格式化代码可以更轻松地处理和发现问题。
  • 另外,IF SQL%NOTFOUND 永远不会为真,因为唯一的 SQL 是游标 FOR 循环的一部分。
  • 问题是因为变量名称与@astentx 突出显示的列名称相同。修正后,更新正常。

标签: oracle plsql triggers sql-update


【解决方案1】:

光标选择UPID = :OLD.PID 的所有行。根据您所说,table2 中的所有行都具有相同的upid 列值,并且等于正在更新的table1.pid现在

UPDATE 语句将修改满足其WHERE 条件的行。他们三个都是一样的:

      WHERE     objID = objID         --> that's 0
            AND objType = objType     --> that's 0 as well
            AND upid = PID            --> that's "old" table1.pid

除了我的第一条语句之外,这意味着table2 中的所有行不仅共享相同的upid,而且它们的objIDobjType 列值是0(至少,这就是你声明)。

此外(正如@astentx 很好地观察到的那样),如果您将变量命名为与列名相同,它的行为就像您输入where 1 = 1 一样,这始终是正确的。对局部变量使用前缀,例如l_ 所以where 子句会变成

      WHERE     objID   = l_objID       --> that's 0
            AND objType = l_objType     --> that's 0 as well
            AND upid    = l_PID         --> that's "old" table1.pid

所以:如果以上所有内容都为真,那么是的 - 触发器将更新 table2 中的所有行。

【讨论】:

    猜你喜欢
    • 2012-01-08
    • 1970-01-01
    • 1970-01-01
    • 2019-02-18
    • 2016-05-01
    • 2013-05-02
    • 2014-03-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多