发生约束冲突时如何调用触发器?

Posted

技术标签:

【中文标题】发生约束冲突时如何调用触发器?【英文标题】:How to call a trigger when constraint violation occurs? 【发布时间】:2018-11-18 20:32:22 【问题描述】:

我遇到了不允许用户输入重复值的情况。如果用户尝试添加重复值,系统会将用户的详细信息保存在审计表中。触发器用于此。我的代码在下面

create or replace trigger tr_add_on_audit_table
before insert on lds_consultant
for each row
declare
uname varchar2(30);
begin
 select username into uname from lds_consultant where username = :NEW.USERNAME;

 if uname <> '' or uname <> null then
  insert into audit_table values(null, null, 'nishan', 'insert', null, null, 'cmd', null, 'LDS_CONSULTANT', 'CONSULTANT_ID',null, null, null);
 end if;
end;

但此代码不会将数据插入到审计表中。

我怎样才能做到这一点?

【问题讨论】:

【参考方案1】:

NULL 不等于也不不同于任何东西。您应该使用IS NULLIS NOT NULL,而不是&lt;&gt;=

类似这样的:

create or replace trigger tr_add_on_audit_table
  before insert on lds_consultant
  for each row
declare
  uname varchar2(30);
begin
 select username 
   into uname 
  from lds_consultant 
  where username = :NEW.USERNAME;

  if uname is not null then          --> this!
    insert into audit_table 
      values(null, null, 'nishan', 'insert', null, null, 'cmd', null, 'LDS_CONSULTANT', 'CONSULTANT_ID',null, null, null);
  end if;
exception
  when no_data_found then
    null;
end;

我包含了异常处理部分,以防 SELECT 不返回任何内容;如果不太可能,请将其删除(或正确处理;我正在做什么NULL;)。此外,如有必要,请处理其他异常。

另外,我建议您命名要插入的所有列。今天,您知道什么值去了哪里,但一两个月后您就会忘记第三个 NULL 值应该是什么意思。

此外,您说不允许用户输入重复的值 - 好吧,这段代码不会让它发生。

最简单的选择是在USERNAME 列上创建一个唯一键约束,并让Oracle 处理重复项。

如果你想自己做,你应该例如

raise_application_error(-20000, 'Duplicate username is not allowed);

但是,这不会将您的 INSERT 保存到表中,因为所有内容都将回滚。为了解决这个问题,创建一个使用 pragma automatic_transaction 并将插入提交到审计表中的过程。

一切都会像这样:

create or replace procedure p_audit as
  pragma autonomous_transaction;
begin
  insert into audit_table 
    values(null, null, 'nishan', 'insert', null, null, 'cmd', null, 'LDS_CONSULTANT', 'CONSULTANT_ID',null, null, null);
  commit;
end;
/
create or replace trigger tr_add_on_audit_table
  before insert on lds_consultant
  for each row
declare
  uname varchar2(30);
begin
 select username 
   into uname 
  from lds_consultant 
  where username = :NEW.USERNAME;

  if uname is not null then
    p_audit;
    raise_application_error(-20000, 'Duplicates are not allowed')
  end if;
exception
  when no_data_found then
    null;
end;
/

但是,再一次,为什么要打扰?唯一性是这里的关键词。

【讨论】:

以上是关于发生约束冲突时如何调用触发器?的主要内容,如果未能解决你的问题,请参考以下文章

在更新触发之前执行时出现约束冲突错误

触发器级联为啥会失败

触发器

在 Redux 中,如果所有 reducer 在动作触发时都被调用,那么是啥阻止了动作之间可能的命名冲突?

调用经过用户身份验证的 http 触发器时发生错误

SQL Server 数据库的维护__触发器