【问题标题】:PL/SQL: Issue implementing triggerPL/SQL:问题实现触发器
【发布时间】:2020-01-05 19:33:21
【问题描述】:

我是 PL/SQL 的新手。我正在尝试在table A 中编写一个trigger insert,只要table B 中有一个insert(要在表B 中插入,以下select 必须返回1 )。

    SELECT 1
    INTO v_exists 
    FROM TFRG V
    WHERE 
        SUBSTR(:NEW.COD_OBJT, 1, 2) = V.CDP
        AND SUBSTR(:NEW.COD_OBJT, 12, 2) = V.CDS
        AND V.CDSIT = 'V'
        AND V.CDG IN (‘E’,’G’);

问题是我不知道如何在我的触发器中包含这个选择:

CREATE OR REPLACE TRIGGER Trigger_name
-- PL/SQL Block
 AFTER INSERT
 ON B FOR EACH ROW
declare

v_exists NUMBER;

begin

begin
    SELECT 1
    INTO v_exists 
    FROM TFRG V
    WHERE 
        SUBSTR(:NEW.COD_OBJT, 1, 2) = V.CDP
        AND SUBSTR(:NEW.COD_OBJT, 12, 2) = V.CDS
        AND V.CDSIT = 'V'
        AND V.CDG IN (‘E’,’G’);


    INSERT INTO A
    (NR);
    VALUES
    (:new.objt);



exception
 when NO_DATA_FOUND then
  null;
end;

exception
  when OTHERS then
  null;
END

【问题讨论】:

  • 那么,它有什么问题(除了when others - 删除它!除非它后面跟着raise,否则它代表你的代码中的一个错误,因为它成功隐藏了可能发生的任何错误)。运行该代码时会发生什么?
  • @Littlefoot,我不知道如何在表 B 中编写插入部分。只要 B 中有插入,触发器就会执行某些操作。要在 B 中插入,select 必须返回 1 . 但是我该怎么写呢?
  • "Insert into B" 在触发器之外完成(例如,在 SQLPlus 提示符下,在 SQL Developer 中,您的 Apex 应用程序中,......真的没关系。触发器将检测该动作并*触发,运行您在其中编写的代码。
  • @porthfind:我很困惑。你知道怎么写INSERT INTO A,却不知道怎么写INSERT INTO B?我们不知道表 B 是什么样子,所以我不明白你会如何期望这里有人给你建议。 ???

标签: oracle plsql database-trigger


【解决方案1】:

如果满足TFRG 的条件,您似乎只想插入表B。解决方案是在不满足时在触发器中抛出异常。这将回滚 B 中的插入并阻止 A 中的插入。

CREATE OR REPLACE TRIGGER Trigger_name
 AFTER INSERT 
 ON B FOR EACH ROW
declare

v_exists NUMBER;

begin

begin
    SELECT 1
    INTO v_exists 
    FROM TFRG V
    WHERE 
        SUBSTR(:NEW.COD_OBJT, 1, 2) = V.CDP
        AND SUBSTR(:NEW.COD_OBJT, 12, 2) = V.CDS
        AND V.CDSIT = 'V'
        AND V.CDG IN (‘E’,’G’);


    INSERT INTO A
    (NR);
    VALUES
    (:new.objt);

exception
 when NO_DATA_FOUND then
  raise_application_exception(-20000, 'No valid record in TFRG');
END;

顺便说一句,这个问题指向一个糟糕的数据模型。如果满足 TFRG 中的某些条件,我们只能插入B 的规则仅在触发器触发时强制执行。另一个会话中的用户可能正在现在更新或删除 TFRG 中的记录,我们的插入将成功,因为他们尚未提交他们的事务。类似地,未来任何针对 TFRG 的 DML 都可能导致追溯违反规则,除非不会发生任何事情,因为没有触发重新验证的机制。外键约束是正确的方法。

另外SUBSTR(:NEW.COD_OBJT, 1, 2) 是一个危险信号。表 B 应该为键的每个组成部分提供单独的列,也许在 TFRG 上有一个复合外键。如果您需要显示 COD_OBJIT,您可以使用虚拟列来实现。 Find out more

【讨论】:

  • 首先,这根本不应该在触发器中。但如果必须的话,我会在一个项目上不同意@APC。这应该是一个 AFTER 触发器。除了“检索” 1 列的值之外,它不需要访问 B 中的任何列,因为它只涉及表 A 的数据和规则。但是,前触发器公开 B 的数据以更改后触发器阻止的位置。触发器因隐藏错误(错误)而臭名昭著,并使调试成为一场噩梦,因此请尽可能保护数据。
【解决方案2】:

根据this 的问题,您不能使用触发器执行此操作。更好的方法是在实际插入表 B 之前添加额外的 WHERE 子句或其他一些逻辑。并且根本不编写该触发器。

【讨论】:

  • 感谢您的提示(我写了已接受的答案),但我觉得这应该是评论而不是答案。
  • 我当然同意你的看法。作为评论,我的回答会更好,但我必须降低声誉才能直接在 OP 问题下发表评论(需要 50 个声誉点 :))
猜你喜欢
  • 2011-08-06
  • 2017-09-14
  • 1970-01-01
  • 2013-06-03
  • 2011-07-29
  • 1970-01-01
  • 2022-01-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多