【问题标题】:Oracle mutating trigger on INSERT插入上的 Oracle 变异触发器
【发布时间】:2018-04-17 11:08:14
【问题描述】:

我正在尝试在 Oracle 8i 中创建一个包含 3 个表的小型数据库,并在其中创建两个触发器。 这是数据库架构:

我已经创建了表格:

CREATE TABLE SYSTEM.Invoices(
   invoice_id   NUMBER              NOT NULL,
   invoice_body_xml CLOB     NOT NULL,
   insertTS  DATE              NOT NULL,
   modifyTS DATE,   
   PRIMARY KEY (invoice_id))
    TABLESPACE SYSTEM;


CREATE TABLE SYSTEM.Invoice_Statuses(
   invoice_id           NUMBER              NOT NULL,
   status               NVARCHAR2(15)       NOT NULL,
   status_details       CLOB,
   transaction_id       NVARCHAR2(50),
   transaction_index    NUMBER,
   request_id           NVARCHAR2(50),
   insertTS             DATE                NOT NULL,
   CONSTRAINT from_statuses_to_invoices
        FOREIGN KEY(invoice_id)
        REFERENCES SYSTEM.INVOICES(invoice_id))
    TABLESPACE SYSTEM;

CREATE TABLE SYSTEM.Open_Invoices(
    invoice_id          NUMBER              NOT NULL,
    invoice_body_xml    CLOB                NOT NULL,
    status              NVARCHAR2(15)       NOT NULL,
    transaction_id      NVARCHAR2(50),
    transaction_index   NUMBER,
    insertTS            DATE                NOT NULL,
   CONSTRAINT from_open_to_invoices
        FOREIGN KEY(invoice_id)
        REFERENCES SYSTEM.INVOICES(invoice_id))
    TABLESPACE SYSTEM;

还有我需要的触发器:

CREATE OR REPLACE TRIGGER after_invoice_insert
AFTER INSERT
   ON SYSTEM.INVOICES
   FOR EACH ROW

BEGIN
   INSERT INTO SYSTEM.INVOICE_STATUSES
   (INVOICE_ID,
   STATUS,
   INSERTTS)
   VALUES
   ( 
    :NEW.invoice_id,
    n'NEW',
    SYSDATE);
END;

还有一个:

CREATE OR REPLACE TRIGGER after_invoice_statuses_insert
AFTER INSERT
   ON SYSTEM.INVOICE_STATUSES
   FOR EACH ROW
DECLARE
    body_xml CLOB;

BEGIN
   SELECT SYSTEM.INVOICES.invoice_body_xml INTO body_xml FROM SYSTEM.INVOICES WHERE SYSTEM.INVOICES.invoice_id = :NEW.invoice_id;
   INSERT INTO SYSTEM.OPEN_INVOICES
   (INVOICE_ID,
   INVOICE_BODY_XML,
   STATUS,
   TRANSACTION_ID,
   TRANSACTION_INDEX,
   INSERTTS)
   VALUES
   ( 
    :NEW.invoice_id,
    body_xml,
    :NEW.status,
    :NEW.transaction_id,
    :NEW.transaction_index,
    SYSDATE);
END;

如您所见,在 OPEN_INVOICES 表中,我需要来自 INVOICES 表的 body_xml,这就是为什么我要使用 select 创建 body_xml。

在此之后,当我尝试插入发票时,我收到此错误:

【问题讨论】:

  • Oracle 8i - 真的吗? 20岁了!
  • 您不应在SYSTEM 架构中创建任何用户对象。
  • @WernfriedDomscheit 没有帮助。如果您发布此内容,请解释为什么不使用 SYSTEM 或使用 cmets 要求澄清。
  • 对,但是使用 SYSTEM 是 MCVE 的一部分(这是一个保留的内部 Oracle 帐户,具有提升的权限,不适用于用户定义的对象)。
  • 从不永远使用 SYS 或 SYSTEM 用户创建您自己的表。只是不要

标签: sql oracle plsql database-trigger oracle8i


【解决方案1】:

您有一个在插入后触发 INVOICES 的触发器。这会触发插入到INVOICE_STATUSES

您还有一个在插入后触发 INVOICE_STATUSES 的触发器,但是在此触发器中,您尝试从表 INVOICES 中进行选择 - 出现错误。

将您的语句和任何触发器中的所有 DML 视为一个 命令。当您在其中插入任何数据时,您不能选择一个表。

您应该将所有逻辑放入一个存储过程并执行该过程。

【讨论】:

    【解决方案2】:

    如果您需要通过触发器完成此操作,那么最好的方法可能是将invoice_body_xml 也存储在INVOICE_STATUSES 中,并将其填充到INVOICES 的触发器中:

    CREATE OR REPLACE TRIGGER after_invoice_insert
     AFTER INSERT
        ON invoices
       FOR EACH ROW
    BEGIN
       INSERT INTO invoice_statuses
         ( invoice_id, status, insertts, invoice_body_xml )
       VALUES
         ( :new.invoice_id, n'NEW', SYSDATE, :new.invoice_body_xml );
    END;
    /
    
    CREATE OR REPLACE TRIGGER after_invoice_statuses_insert
     AFTER INSERT
        ON invoice_statuses
       FOR EACH ROW
    BEGIN
        INSERT INTO open_invoices
          ( invoice_id, invoice_body_xml, status, transaction_id, transaction_index, insertts )
       VALUES
         ( :new.invoice_id, :new.invoice_body_xml, :new.status, :new.transaction_id, :new.transaction_index, SYSDATE );
    END;
    /
    

    【讨论】:

      【解决方案3】:

      我建议不要尝试折叠、旋转和破坏一堆触发器来执行所需的 INSERT、SELECT 等操作,我建议您编写一个类似于以下内容的程序来创建您的发票:

      CREATE OR REPLACE PROCEDURE CREATE_INVOICE
        (pinInvoice_id       IN NUMBER,
         pinInvoice_body_xml IN CLOB)
      IS
      BEGIN
        INSERT INTO INVOICES
          (INVOICE_ID,
           INVOICE_BODY,
           INSERTTS)
        VALUES
          (pinInvoice_id,
           pinInvoice_body_xml,
           SYSDATE);
      
        INSERT INTO INVOICE_STATUSES
          (INVOICE_ID,
           STATUS,
           INSERTTS)
        VALUES
          (pinInvoice_id,
           n'NEW',
           SYSDATE);
      
        INSERT INTO OPEN_INVOICES
          (INVOICE_ID,
           INVOICE_BODY_XML,
           STATUS,
           TRANSACTION_ID,
           TRANSACTION_INDEX,
           INSERTTS)
        VALUES
         (pinInvoice_id,
          pinInvoice_body_xml,
          n'NEW',
          ???,  -- don't know where this comes from
          ???,  -- don't know where this comes from
          SYSDATE);
      END CREATE_INVOICE;
      

      您可能仍想使用触发器来设置 INSERTTS 和 MODIFYTS 等字段。

      在执行此操作时,我发现需要设置 OPEN_INVOICES 中的几个字段,但是(据我所知)它们没有被初始化。这可能是您想要调查的内容。

      祝你好运。

      【讨论】:

        猜你喜欢
        • 2018-04-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-08-25
        • 2014-06-28
        • 1970-01-01
        • 1970-01-01
        • 2012-03-16
        相关资源
        最近更新 更多