【问题标题】:Insert value on second trigger with value from first trigger PL\SQL使用来自第一个触发器 PL\SQL 的值在第二个触发器上插入值
【发布时间】:2018-03-27 08:43:05
【问题描述】:

您好,我仅在满足条件时才尝试在第二个触发器中使用第一个触发器的新 ID 插入值,但我被卡住了。

table1_trg 有效

 CREATE TABLE table1 (
  id             NUMBER(9,0)   NOT NULL,
  subject        VARCHAR2(200) NOT NULL,
  url_address    VARCHAR2(200) NOT NULL,
)

 CREATE OR REPLACE TRIGGER table1_trg
BEFORE INSERT ON table1
FOR EACH ROW

BEGIN
  SELECT table1_seq.NEXTVAL
  INTO   :new.id
  FROM   dual;
END;

/

CREATE OR REPLACE TRIGGER table1_url
    BEFORE INSERT ON table1
    FOR EACH ROW

WHEN (NEW.subject = 'Task')
BEGIN
    INSERT INTO CSB.table1 (url_address)
    VALUES ('blabla.com?' || :new.id);
END;
/

我只插入主题,但之后我收到subject 不能为空的异常。

INSERT INTO corp_tasks_spec (subject) VALUES ('Task')

有什么解决办法吗?

【问题讨论】:

  • 您是否真的希望它创建第二行 - 因此,当您插入任务记录时,它还会使用第一行的 ID 使用该 URL 创建一个完全独立的行?第一行的 URL 值是什么,或者第二行的主题是什么?您似乎更有可能只想得到一个同时设置了 ID 和 URL 的单行,对吧?

标签: sql oracle plsql


【解决方案1】:

您不应该将新记录插入到同一个表中,而应该修改您已经插入的行的列值 - 触发器正在触发该行。由于第二次插入,您会收到错误 - only 指定 URL 值,而不是主题或 ID(尽管第一个触发器将再次触发并为该新行设置 ID - 所以它抱怨这个主题)。

在旧版本的 Oracle 中,在同一触发点上设置两个触发器可能很困难,因为它们触发的顺序无法保证 - 例如,您的第二个触发器可能在第一个触发之前触发,并且 ID 尚未设置。您可以使用FOLLOWS 控制更高版本(从 11g 开始)中的顺序:

CREATE OR REPLACE TRIGGER table1_url
    BEFORE INSERT ON table1
    FOR EACH ROW
    FOLLOWS table1_trg

WHEN (NEW.subject = 'Task')
BEGIN
    :NEW.url_address := 'blabla.com?' || :new.id;
END;
/

现在在第一个触发器之后触发,因此设置 ID,并为该行中的 URL 分配一个值,而不是尝试创建另一行:

INSERT INTO table1 (subject) VALUES ('Task');

1 row inserted.

SELECT * FROM table1;

        ID SUBJECT    URL_ADDRESS         
---------- ---------- --------------------
         2 Task       blabla.com?2        

但是你在这里并不需要两个触发器,你可以这样做:

DROP TRIGGER table1_url;

CREATE OR REPLACE TRIGGER table1_trg
BEFORE INSERT ON table1
FOR EACH ROW
BEGIN
  :NEW.id := table1_seq.NEXTVAL; -- no need to select from dual in recent versions
  IF :NEW.subject = 'Task' THEN
    :NEW.url_address := 'blabla.com?' || :new.id;
  END IF;
END;
/

然后该触发器生成 ID 并设置 URL:

INSERT INTO table1 (subject) VALUES ('Task');

1 row inserted.

SELECT * FROM table1;

        ID SUBJECT    URL_ADDRESS         
---------- ---------- --------------------
         2 Task       blabla.com?2        
         3 Task       blabla.com?3        

当然,对于除 Task 之外的任何内容,您都必须将 URL 指定为插入的一部分,否则会出错,因为那是一个非空列。

【讨论】:

    【解决方案2】:

    创建序列

    CREATE SEQUENCE table1_SEQ
      START WITH 1
      MAXVALUE 100000
      MINVALUE 1
      NOCYCLE
      NOCACHE
      NOORDER;
    

    创建触发器

    CREATE OR REPLACE TRIGGER table1_TRG
    Before Insert 
    ON  table1 Referencing New As New Old As Old 
    For Each Row
    Declare V_Val Number; 
    Begin 
            Select table1_SEQ.NextVal into V_Val From Dual;
        If Inserting Then 
            :New.id:= V_Val;
        End If; 
    End;
    /
    

    【讨论】:

    • 但它是第一次触发的答案。我不知道第二个答案。
    • 我需要添加那行IF :NEW.subject = 'Task' THEN :new.url_address:= 'blabla.com?'; END IF;
    • 你必须把所有的东西都写到这个触发器中,因为如果你不这样做,那么它会显示一个突变错误..
    • 这并没有解决“主题不能为空”的问题
    • 'If Inserting` 始终为真,因为触发器仅在插入时触发。除了添加一个额外的变量来保存序列值之外,我不确定这与 OP 的代码有何显着不同?而且它不处理插入在另一个触发器中抛出的错误。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-16
    • 2014-12-06
    • 2018-12-31
    • 2020-01-28
    • 2022-10-22
    相关资源
    最近更新 更多