【问题标题】:PL/SQL Trigger to update another table from INSERT on one tablePL/SQL 触发器从一个表上的 INSERT 更新另一个表
【发布时间】:2025-12-20 23:50:16
【问题描述】:

我正在使用 SQL 和 Oracle 数据库,需要一些帮助 - 我很难理解触发器。

当我在表 A 中插入一行时,我需要一个触发器,以便它更新表 B 上的一行:特别是主键与刚刚添加到表 A 的行的相应外键匹配的行。

例如,表 A 中的列 X 是引用表 B 中的列 Y(主键)的外键。当我向表 A 添加一行时,我需要表 B 的列 Z 将 1 添加到其列 X = Y 列的行中的数值。

根据我对触发器的有限理解,这是我迄今为止在 SQL 中所能得到的,以防万一它有帮助(我意识到它不是很好,将其视为伪代码):

CREATE OR REPLACE TRIGGER test_trig
AFTER INSERT OR UPDATE ON tableA
FOR EACH ROW

BEGIN
  UPDATE tableB
  SET columnZ = columnZ + 1
  WHERE tableA.columnX = tableB.columnY;
END test_trig;
/

谢谢

【问题讨论】:

    标签: database oracle plsql


    【解决方案1】:

    我猜您正在为 (A) 保留历史 (B) 计数器或 (C) 数据完整性问题实施某种机制。 如果是这种情况,我建议使用 pl/sql 包执行更新,该包将处理所有必要的更新/其他 DML 操作。 应用程序通过 pl/sql 包更新数据是最佳实践。通过这种方式,您可以在内部控制流程,并且更易于维护。另外,当您忘记在该表上有触发器时,您可以在将来保存自己的问题。

    我可以为您提供一个关于触发器的提示 - 在您决定使用触发器之前,请确保您已经用尽了所有其他可能性

    【讨论】:

      【解决方案2】:

      如果 tableB.columnZ 表示被引用的 tableA 记录的计数,那么除非 tableA 的引用列可以更改,否则触发 tableA 的 UPDATE 是没有意义的。

      第一次情况:tableA.ReferenceColumn 不变:

      CREATE OR REPLACE TRIGGER test_trig
      AFTER INSERT ON tableA
      FOR EACH ROW
      BEGIN
      
        UPDATE tableB
        SET columnZ = columnZ + 1
        WHERE tableB.columnX = :NEW.columnX;
      END test_trig;
      /
      

      第二种情况:tableA.ReferenceColumn 确实发生了变化:

      CREATE OR REPLACE TRIGGER test_trig
      AFTER INSERT OR UPDATE OF columnX ON tableA
      FOR EACH ROW
      
      BEGIN
      
        IF UPDATING AND nvl(:OLD.columnX,0) <> 0 THEN
            UPDATE tableB
            SET columnZ = columnZ - 1
            WHERE tableB.columnX = :OLD.columnX;
        END IF:
      
        IF nvl(:NEW.columnX,0) <> 0 THEN
            UPDATE tableB
            SET columnZ = columnZ + 1
            WHERE tableB.columnX = :NEW.columnX;  
        END IF;
      
      END test_trig;
      /
      

      第三种情况:tablaA 记录可以删除:

      CREATE OR REPLACE TRIGGER test_trig
      AFTER INSERT OR DELETE OR UPDATE OF columnX ON tableA
      FOR EACH ROW
      
      BEGIN
        IF (UPDATING OR DELETING) AND nvl(:OLD.columnX,0) <> 0 THEN
            UPDATE tableB
            SET columnZ = columnZ - 1
            WHERE tableB.columnX = :OLD.columnX;
        END IF:
      
        IF nvl(:NEW.columnX,0) <> 0 THEN
            UPDATE tableB
            SET columnZ = columnZ + 1
            WHERE tableB.columnX = :NEW.columnX;  
        END IF;
      END test_trig;
      /
      

      【讨论】:

        【解决方案3】:

        试试这个:

        语法将是

        CREATE OR REPLACE TRIGGER test_trig
        AFTER INSERT OR UPDATE ON tableA
        FOR EACH ROW
        
        BEGIN
          UPDATE tableB
          SET columnZ = columnZ + 1
          WHERE tableB.columnX = :NEW.columnX;
        END test_trig; 
        /
        

        :new.columnX 引用表A columnX。

        【讨论】:

          【解决方案4】:

          足够好的开始。

          首先 - 让我们解决这个问题 - 这没有很好地标准化 - 您描述的值似乎应该在运行时而不是在数据操作时计算。

          考虑以下几点:

          插入 = +1 到列 - 好的

          更新 = ?我想并不总是对列 +1 - 可能只有在修改某些其他数据时。例如 - 如果我更新表一个集合 col1=col1。也许你想要的也许不是。

          删除 = ?删除是否意味着列的-1?

          语法:

          WHERE tableA.columnX = tableB.columnY;
          

          应该是

          WHERE :new.columnX = tableB.columnY;
          

          【讨论】:

            最近更新 更多