PL/SQL 触发器在插入语句之前检查值

Posted

技术标签:

【中文标题】PL/SQL 触发器在插入语句之前检查值【英文标题】:PL/SQL Trigger to check value before insert statement 【发布时间】:2021-03-17 17:14:38 【问题描述】:

我是 PL/SQL 的新手,我在尝试实现的触发器方面遇到问题。

触发器的目的是在插入表之前检查货币值,以查看是否有人在插入过程中出错。如果有,他们将收到一条消息,说明该值不正确。这些值以十亿为单位,所以现在我只是检查输入的值是否高于 10000。

我目前拥有的触发器是;

CREATE TRIGGER Check_Value
BEFORE INSERT OR UPDATE OF "Potential Annual Value By 2026" ON AIPOTENTIALVALUEFORHEALTHCARE
BEGIN
IF (NEW."Potential Annual Value By 2026" < 10000.00) THEN
DBMS_OUTPUT.put_line('Value typed was incorrect');
ELSIF (NEW."Potential Annual Value By 2026" >= 10000.00) THEN
INSERT INTO AIPOTENTIALVALUEFORHEALTHCARE VALUES(NEW.ValueID, NEW.ApplicationID, NEW."Application Name", NEW.KeyDriverForAdoptionID, NEW."KeyDriverDescription", NEW."Potential Annual Value By 2026");
END IF;
END;

由于错误,这将不起作用:

PLS-00201: identifier NEW.'Potential Annual Value By 2026' must be declared

我的猜测是我错误地设置了触发器,并且它不知道在运行触发器时要检查哪个值。根据一些研究,我尝试使用 .NEW 将语句的值传递到触发器中,但是我不确定这是否是正确的实现。

我已经尝试过已经发布的方法;

CREATE TRIGGER Check_Value
BEFORE INSERT OR UPDATE OF "Potential Annual Value By 2026" ON AIPOTENTIALVALUEFORHEALTHCARE
BEGIN
  IF (:NEW."Potential Annual Value By 2026" < 10000.00) THEN
    DBMS_OUTPUT.put_line('Value typed was incorrect');
  ELSIF (:NEW."Potential Annual Value By 2026" >= 10000.00) THEN
    INSERT INTO AIPOTENTIALVALUEFORHEALTHCARE VALUES
      (:NEW.ValueID, :NEW.ApplicationID, :NEW."Application Name", 
       :NEW.KeyDriverForAdoptionID, :NEW."KeyDriverDescription", 
       :NEW."Potential Annual Value By 2026");
  END IF;
END;

并收到另一个错误:

ORA-04082: NEW or OLD references not allowed in table level triggers
04082. 00000 -  "NEW or OLD references not allowed in table level triggers"
*Cause:    The trigger is accessing "new" or "old" values in a table trigger.
*Action:   Remove any new or old references.

如果此错误表明我不能在表级触发器中使用 NEW 引用,我如何能够在插入语句提交之前验证它的内容?

【问题讨论】:

顺便说一句,你真的,真的REALLY不想在混合大小写的情况下命名列或任何其他对象嵌入空格(更新“到 2026 年的潜在年度价值”)。每当您发现自己必须用双引号将对象名称括起来时,您都需要重新考虑。然后再次。又一次。 【参考方案1】:

NEW 关键字和 FOR EACH ROW 子句之前缺少冒号。此外,您不需要(也不得)在触发器中重新发出 INSERT,无论如何都会发生(如果没有引发错误):

CREATE TRIGGER Check_Value
BEFORE INSERT OR UPDATE OF "Potential Annual Value By 2026" ON AIPOTENTIALVALUEFORHEALTHCARE
FOR EACH ROW
BEGIN
  IF (:NEW."Potential Annual Value By 2026" < 10000.00) THEN
    RAISE_APPLICATION_ERROR(-20001, 'Value typed was incorrect');
  END IF;
END;

我确定这只是一个训练示例,但 DBMS_OUTPUT.PUT_LINE 不是向用户提出错误的合适方法,因为它的输出只能在使用 SQL Developer 等开发工具时看到。使用RAISE_APPLICATION_ERROR。而且它实际上并没有引发异常,所以它根本不会阻止插入。

事实上,使用 CHECK 约束可能会更好地完成此检查 - 假设列值决不能低于 10000:

ALTER TABLE AIPOTENTIALVALUEFORHEALTHCARE
   ADD CONSTRAINT AIPOTENTIALVALUEFORHEALTHCARE_CHK_VALUE
      CHECK ("Potential Annual Value By 2026" >= 10000);

【讨论】:

我应该提到我已经尝试过这种方法但它不起作用,我将使用收到的错误编辑帖子。是的,这只是为了我自己的兴趣与 Oracle SQL Developer 的一个小游戏,但我会研究 Raise_Application_Error。 @JohnSortley24 答案已更新 - 每行都需要 谢谢,我认为 FOR EACH ROW 用于循环遍历表中的每一行,这就是我没有包含它的原因。您的逻辑对此要好得多,下次我会牢记插入语句。如果将检查约束添加到要验证的每个字段,是否可以自定义如果不满足条件会引发什么错误?从理论上讲,我可以将约束命名为错误消息,对吗?或者有没有更好的方法 使用check constraint 是可行的方法,如果违反,您将收到异常“ORA-02290:检查约束”,后跟方案名称和约束名称。见fiddle

以上是关于PL/SQL 触发器在插入语句之前检查值的主要内容,如果未能解决你的问题,请参考以下文章

使用 PL/SQL 在触发器中中止插入/更新操作

基于变化表中的值在插入之前触发 PL/SQL 触发器

在使用 Entity Framework 数据库优先在表上插入行之前,如何从 PL/SQL 执行触发器?

PL/SQL 创建一个根据日期范围检查 SYSDATE 的触发器

PL/SQL:检查触发器中的所有行后运行包

PL/SQL 触发器不工作