【问题标题】:Oracle Trigger creation - table is mutating; trigger may not read or modify itOracle 触发器创建 - 表正在变异;触发器可能无法读取或修改它
【发布时间】:2013-07-23 19:06:49
【问题描述】:

由于表正在变异,因此以下触发器不起作用,因为我认为触发器中的 SQL 语句无法针对变异表执行,但是由于我不在 11g 上,因此我无法创建复合触发器。我尝试在声明部分包含PRAGMA AUTONOMOUS TRANSACTION;,但是这不会编译。谁能给我最好的解决方案?

create or replace 
trigger fb_pers_id_check2_tr
  --after insert on ifsapp.person_info_tab
  before insert on ifsapp.person_info_tab      
for each row
begin
  declare
--  pragma autonomous_transaction;
    v_pid_ person_info_tab.person_id%type;
    format_name_ person_info_tab.name%type;
  begin

  v_pid_ := :new.person_id;

  select regexp_replace(upper(:new.name), '\W')
    into format_name_
  from ifsapp.person_info_tab
  where person_id = v_pid_;

  if length(v_pid_) < 3 and (length(format_name_) < 21 and v_pid_ <> format_name_) then
    raise_application_error(-20001, 'Person ID: ' || v_pid_ || 'is not valid, please enter a valid     Person ID, e.g. "' || format_name_ || '".');
  end if;
end;
end fb_pers_id_check2_tr;

注意简而言之,此触发器旨在阻止用户设置长度小于 3 个字符且不等于变量“format_name_”(如果长度小于 21 个字符)的用户 ID。

【问题讨论】:

  • 那么为什么这不是插入前触发器而不是检查length(:new.person_id) 并与格式化的:new.name 进行比较?为什么需要看表版本?
  • 我已经编辑了问题中的代码以反映您的建议,但是这样做时会返回错误“未找到数据”。
  • 如果您要插入一个新行,它将不会在表中找到。

标签: oracle plsql triggers mutating-table


【解决方案1】:

Oracle 不允许行触发器读取或修改定义触发器的表。但是,如果 PERSON_ID 是 PERSON_INFO_TAB 上的 PRIMARY 或 UNIQUE 键(考虑到它在单例 SELECT 中使用,这似乎是这种情况),您实际上不需要读取表 - 只需在适当的情况下使用 OLD 或 NEW 值:

create or replace trigger fb_pers_id_check2_tr
  before insert on ifsapp.person_info_tab
  for each row
declare
  v_pid_ person_info_tab.person_id%type;
  format_name_ person_info_tab.name%type;
begin
  v_pid_ := :new.person_id;

  format_name_ := REGEXP_REPLACE(UPPER(:new.name), '\W');    

  if length(v_pid_) < 3 and
     length(format_name_) < 21 and
     v_pid_ <> format_name_
  then
    raise_application_error(-20001, 'Person ID: ' || v_pid_ ||
                            ' is not valid, please enter a valid' ||
                            ' Person ID, e.g. "' || format_name_ || '".');
  end if;
end fb_pers_id_check2_tr;

这里的代码正在检查 NAME 的 NEW 值(我认为这是正确的,因为它似乎正在验证输入),但如果目的是检查 OLD 值,则将 :NEW 更改为 :OLD 很简单REGEXP_REPLACE 调用。

分享和享受。

【讨论】:

  • 我已将其更改为 BEFORE INSERT 触发器,以匹配 OP 对问题的更改。我相信答案仍然有效 - 引用欧比旺的话,“使用 :NEW 值,卢克!”。分享和享受。
  • 感谢大家的帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-20
  • 2022-10-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多