【问题标题】:how to prevent inserting empty data into the table row using trigger in pl-sql如何防止在pl-sql中使用触发器将空数据插入表行
【发布时间】:2013-03-15 01:43:42
【问题描述】:

我正在尝试在 PL/SQL 中创建一个 before insert Trigger,以防止将空数据插入到表行中。 (强制执行非空条件并防止插入数字或特殊字符的触发器。

这是我创建的表。

CREATE TABLE CUSTOMER 
(
  CUSTOMER_ID INTEGER 
, CUST_FORENAME VARCHAR2(50) NOT NULL 
, CUST_SURNAME VARCHAR2(50) NOT NULL 
, GENDER CHAR(1) 
, EMAIL_ADDRESS VARCHAR2(30) NOT NULL 
, CONSTRAINT CUSTOMER_PK PRIMARY KEY (CUSTOMER_ID)
  ENABLE 
);

还有我创建的触发器。

create or replace
TRIGGER CUS_MAND before insert OR update on CUSTOMER
begin
  CASE
    WHEN :NEW.CUST_FORENAME = NULL
      THEN DBMS_OUTPUT.PUT_LINE ('Please enter customer forename.');
    WHEN :NEW.CUST_SURNAME = NULL
      THEN DBMS_OUTPUT.PUT_LINE ('Please enter customer surname.');
    WHEN :NEW.EMAIL_ADDRESS = NULL
      THEN DBMS_OUTPUT.PUT_LINE ('Please enter customer email address.');
  END CASE;
END;

但是这个触发器没有成功。有人可以帮我解决这个问题吗?

【问题讨论】:

  • 这是触发器的错误用法。依靠 NOT NULL 约束来强制执行 NOT NULL-ness 并根据需要使用客户端验证。
  • 另外,您的问题应该描述“此触发器无法成功工作”的方式。
  • 客户端验证是指在将信息发送到数据库之前检查应用程序的客户端部分是否已完成所有必填字段。

标签: sql plsql oracle11g sqlplus plsqldeveloper


【解决方案1】:

正如@APC 所指出的,为此目的使用 NOT NULL 约束比使用触发器更有意义。

但是,如果您想使用触发器,则应该引发错误,而不是仅仅打印到 DBMS_OUTPUT,因为

  • 打印消息不会阻止插入错误数据
  • 通常,INSERTS / UPDATES 将由某种客户端程序运行,而 DBMS_OUTPUT 不会显示在此客户端程序中

除此之外,您的触发器中还有几个错误:

  • 您需要将触发器声明为 FOR EACH ROW,否则,您将无法使用 :NEW 和 :OLD(因为您的触发器将在每个语句中触发一次,而不是每个)
  • 您的 CASE 语句缺少 DEFAULT 分支,因此如果所有检查都成功,您将在执行过程中收到错误;我会改用 IF

一种可能的解决方案:

create or replace trigger CUS_MAND before insert OR update on CUSTOMER
for each row        
begin
  if :NEW.CUST_FORENAME is NULL THEN
    RAISE_APPLICATION_ERROR(-20001,
                            'Please enter customer forename.');
  end if;
  if :NEW.CUST_SURNAME is NULL THEN
    RAISE_APPLICATION_ERROR(-20002,
                            'Please enter customer surname.');
  end if;
  if :NEW.EMAIL_ADDRESS is NULL THEN
    RAISE_APPLICATION_ERROR(-20003,
                            'Please enter customer email address.');
  END if;
END;

在这里,我使用 RAISE_APPLICATION_ERROR 来引发用户定义的异常;您可以对所有错误使用相同的错误编号 (-20001),也可以使用编号来区分它们。

【讨论】:

    【解决方案2】:

    您以错误的方式检查空值:

    :NEW.CUST_FORENAME = NULL
    

    空值检查必须使用“is null”或“is not null”。相等运算符不起作用。没有什么与 NULL 相同或不同。

    所以,如果 A := null:

    a = Null => false
    a != null => false
    a is null => true
    a is not null => false
    

    此外,您的触发器应该是 Frank Schmitt 指出的“FOR EACH ROW”。

    如果您的验证很简单,使用非空约束或检查约束可能是最佳选择。

    【讨论】:

    • 触发器没有意义...您可以在 OPs 情况下使用 not null 或检查约束...
    • 你不能;但您可以使用检查约束。
    • 正如@Ben 所说,在这个问题中,使用触发器进行 NULL 检查是没有意义的。您可以编造需要进行更复杂检查的情况,并以不同的方式完成,但如果我们开始走这条路(我们回答 OP 没有问的问题),我们很快就会有一个数据库- 数据库实现,然后可能克苏鲁怜悯我们。 (尽管,正如克苏鲁在黑暗的疯狂幻象中告诉我的那样,他更喜欢番茄酱而不是仁慈)。分享和享受。
    • 完全同意。那么,我是否已经回答了这个问题?您正在将接受的答案减少为“不要那样做,这很愚蠢”,而不是真正回答它。同时,当我试图回答它时,你在批评我,而不是对它是如何出现的做出假设。
    • 我不同意你的评论@jagra。最好的答案是“不要那样做;这就是你应该做的事情以及原因。如果你对完成你正在做的事情完全下定决心,那么这就是你应该如何去做”。你没有回答错,我只是不认为你回答得很好。看,我猜,弗兰克的比较答案。他清楚地确定了这样做的最佳方式,然后指出了哪里出了问题并包含了代码来演示(不是我会这样编码)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-08
    • 1970-01-01
    • 2020-12-02
    • 1970-01-01
    • 2020-08-29
    相关资源
    最近更新 更多