【问题标题】:Oracle trigger conflict with nullOracle 触发器与 null 冲突
【发布时间】:2012-09-18 09:02:51
【问题描述】:

首先,这是一个作业,所以大多数你想要建议的非常酷的预写功能,我都不会被允许使用。

我有几个表都有字段

creation_date
created_by
last_update_date
last_updated_by

我需要编写一个触发器来填充这些以进行创建或更新。问题是,这些表的空值对我来说是个问题。示例:

CREATE TABLE parts
(
pno                NUMBER,
pname              VARCHAR2(50) NOT NULL,
qoh                NUMBER       NOT NULL,
price              NUMBER(5,2),
reorder_level      NUMBER(2),
creation_date      DATE         NOT NULL,
created_by         VARCHAR2(10) NOT NULL,
last_update_date   DATE         NOT NULL,
last_updated_by    VARCHAR2(10) NOT NULL,
CONSTRAINT parts_PK PRIMARY KEY (pno))

这些 NOT NULL 是给我的,我不能更改它们。所以我很难概念化这个。

  • 如果我的触发器在创建字段之前添加了这些值,我无法在这些字段为空的情况下执行 INSERT INTO,因为它们不是 NULL。
  • 如果我的触发器在创建字段后添加这些值,我会收到编译错误 ORA-00903 和 00922。无效的表名和无效的选项。

我在想我的触发器看起来像

CREATE OR REPLACE TRIGGER pcreate
  BEFORE UPDATE on parts
  FOR EACH ROW
BEGIN
  UPDATE
    SET creation_date = SYSDATE;
    SET created_by = USER;
    SET last_update_date = SYSDATE;
    SET last_updated_by = USER;
END;
/

CREATE OR REPLACE TRIGGER pchange
  BEFORE UPDATE on parts
  FOR EACH ROW
BEGIN
  UPDATE
    SET last_update_date = SYSDATE;
    SET last_updated_by = USER;
END;
/
repeat for the other tables

我可能被允许使用 UPSERT,但我真的不知道它是如何工作的。欢迎任何建议。我真的很想学习,所以任何其他建议都值得赞赏。

编辑:

我的不承认触发器的包如下。我需要调用包内的触发器吗?

CREATE OR REPLACE PACKAGE process_orders 
AS
  PROCEDURE add_order (p_cno IN NUMBER, p_eno IN NUMBER, p_received IN DATE);
  PROCEDURE add_order_details (p_ono IN NUMBER, p_pno IN NUMBER, p_qty IN NUMBER);
  PROCEDURE ship_order (p_ono IN NUMBER, p_sdate IN DATE);
  PROCEDURE delete_order (p_ono IN NUMBER);
  FUNCTION total_emp_sales (f_eno IN NUMBER) RETURN NUMBER;
END process_orders;
/

CREATE OR REPLACE PACKAGE BODY process_orders 
AS
  PROCEDURE add_order (p_cno IN NUMBER, p_eno IN NUMBER, p_received IN DATE) 
  IS
  ao_emsg       VARCHAR2(100);
  p_rec_today   DATE;
  BEGIN
    SELECT SYSDATE INTO p_rec_today FROM dual;
    IF p_received is null THEN
        INSERT INTO orders (ono, cno, eno, received)
        VALUES(order_number_seq.NEXTVAL,p_cno,p_eno,p_rec_today);
    ELSE
        INSERT INTO orders (ono, cno, eno, received)
    VALUES(order_number_seq.NEXTVAL,p_cno,p_eno,p_received);
    END IF;

  EXCEPTION
    WHEN OTHERS THEN
      ao_emsg := substr(SQLERRM,1,100);
      INSERT INTO orders_errors (ono,transaction_date,message)
      VALUES(order_number_seq.CURRVAL,SYSDATE,ao_emsg);
  END;
  --Etc. Procedures
END;
/

【问题讨论】:

  • 您的问题最初讨论了PARTS 表和PARTS 表上的触发器。您的编辑讨论了在ORDERS 表上定义的过程。您在将数据插入PARTS 表时遇到问题吗?或者只是ORDERS 表?如果您在使用PARTS 表时遇到问题,因为您已经发布了该表的定义,您能否发布生成插入PARTS 的错误的代码?您能否发布完整的错误消息和您定义的触发器?
  • 我想通了,谢谢你的帮助。该分配有 5 个包含这些日期和用户列的表,但它说“为这 3 个表创建触发器”,因此错误是引用了我没有为其编写触发器的两个表之一。

标签: sql oracle triggers null sqlplus


【解决方案1】:

在您的触发器中,您只需修改:new 记录。你的触发器看起来像

CREATE OR REPLACE TRIGGER parts_before_insert
  BEFORE INSERT on parts
  FOR EACH ROW
BEGIN
  :new.creation_date := SYSDATE;
  :new.created_by := USER;
  :new.last_update_date := SYSDATE;
  :new.last_updated_by := USER;
END;

CREATE OR REPLACE TRIGGER parts_before_update
  BEFORE UPDATE on parts
  FOR EACH ROW
BEGIN
  :new.last_update_date := SYSDATE;
  :new.last_updated_by := USER;
END;

在您的INSERT 语句中,您将省略这四列并让触发器填充这些值。例如(显然,您的主键将来自序列之类的东西,而不是硬编码)

SQL>  insert into parts( pno, pname, qoh, price, reorder_level )
  2     values( 1, 'Widget', 10, 100, 75 );

1 row created.

SQL> select *
  2    from parts;

       PNO PNAME                                                     QOH
---------- -------------------------------------------------- ----------
     PRICE REORDER_LEVEL CREATION_ CREATED_BY LAST_UPDA LAST_UPDAT
---------- ------------- --------- ---------- --------- ----------
         1 Widget                                                     10
       100            75 26-SEP-12 SCOTT      26-SEP-12 SCOTT

【讨论】:

  • @caleb.breckon - 我用INSERT 语句的示例更新了我的答案。
  • 尝试为 creation_date 输入 NULL 值时出现错误
  • @caleb.breckon - 你遇到了什么错误?您正在执行的语句是什么?
  • 我将文件分成 .sql、.pkg 和 .trg。 .trg 在表创建和一些基线数据输入之间在 .sql 内执行。我的 .sql 文件中的这些 INSERTS 被创建。但是,当我尝试从包中执行一些创建其他插入的过程时,这些过程会给我一个“尝试为 creation_date 插入 NULL”错误”。我的包不应该在 .sql 中创建触发器后确认我的触发器吗?
  • 澄清一下:这个完全相同的语句在触发文件执行后立即使用时有效,但在我的 pkg 中使用它时会出现错误。插入客户 (cno,cname,street,zip,phone) VALUES(c_number_seq.NEXTVAL,'Ron Swanson','342 Pawnee Avenue','20650','301-862-1820') /
【解决方案2】:

在您的情况下,无需在触发器中执行 UPDATE 语句。只需使用:new 为列分配新值。

CREATE OR REPLACE TRIGGER pchange
  BEFORE UPDATE on parts
  FOR EACH ROW
BEGIN
  :new.last_update_date = SYSDATE;
  :new.last_updated_by = USER;
END;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-03-08
    • 2017-06-10
    • 1970-01-01
    • 1970-01-01
    • 2015-09-18
    • 1970-01-01
    • 2011-09-21
    • 2015-01-02
    相关资源
    最近更新 更多