如何在Oracle PL / SQL中实现AFTER INSERT触发器?

问题描述

我试图在PLSQL中插入触发器后实现。
目标是检查每个客户是否有多行(> 1)具有特定状态。
如果愿意,我想抛出一个异常并回滚插入。

我正在努力实现无警告查询,这会在插入过程中导致错误。
我该如何管理呢?
这是我实现的触发器,我想需要进行一些更改。

CREATE TRIGGER blatrigger
    AFTER INSERT
    ON BLATABLE
    REFERENCING NEW AS NEW OLD AS OLD
    FOR EACH ROW
DECLARE
    exception_name EXCEPTION;
    PRAGMA EXCEPTION_INIT (exception_name,-20999);
BEGIN
    if (select count(*) as counter from BLATABLE where CLIENTID = :NEW.CLIENTID and STATUS='PENDING').counter > 1
    THEN
        raise exception_name;
    END IF;
END;

这是表格本身:

create table BLATABLE
(
    ID            NUMBER(19) not null primary key,CLIENTID     NUMBER(10),CREATED       TIMESTAMP(6),STATUS        VARCHAR2(255 char)
);

解决方法

目标是检查每个客户是否有多行(> 1)具有特定状态。如果是这样,我想提出一个例外并回滚插入。

无需触发器。看起来一个简单的唯一约束应该可以在这里完成工作:

create table blatable (
    id            number(19) not null primary key,clientid      number(10),created       timestamp(6),status        varchar2(255 char),constraint blaconstraint unique (clientid,status)
);

唯一约束可防止整个表中(clientid,status)上的重复项。如果DML操作(插入,更新)尝试生成重复项,则会引发错误并回滚该操作。

如果在另一端,每个用户只允许一个“ PENDING”状态,则可以按如下方式使用唯一索引:

create unique index bla_index
    on blatable( (case when status = 'PENDING' then clientid end) );
,

使用语句级触发器,而不是行级,方法是删除FOR EACH ROW,然后转换为以下代码:

CREATE OR REPLACE TRIGGER blatrigger
  AFTER INSERT ON BLATABLE
  REFERENCING NEW AS NEW OLD AS OLD

DECLARE
  counter        INT;
  exception_name EXCEPTION;
  PRAGMA EXCEPTION_INIT(exception_name,-20999);
BEGIN
  SELECT MAX(COUNT(*))
    INTO counter
    FROM BLATABLE
   WHERE STATUS = 'PENDING'
   GROUP BY CLIENTID;
     
  IF counter > 1 THEN
    RAISE exception_name;
  END IF;
END;
/

其中

  • 需要从IF .. THEN有条件的条件中删除SELECT语句
  • 很可能在行级触发器的情况下会引起变异表错误

Demo

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...