Создание триггера Oracle - таблица изменяется; триггер не может прочитать или изменить его

Поскольку таблица мутирует, следующий триггер не работает, поскольку я считаю, что оператор 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 символа.


person pwlm    schedule 24.07.2013    source источник
comment
Так почему же это не триггер перед вставкой, чем проверка length(:new.person_id) и сравнение с отформатированным :new.name? Зачем нужно смотреть на табличную версию?   -  person Alex Poole    schedule 24.07.2013
comment
Я отредактировал код в вопросе, чтобы отразить ваше предложение, однако при этом он возвращает ошибку «Данные не найдены».   -  person pwlm    schedule 24.07.2013
comment
Если вы вставляете новую строку, она не будет найдена в таблице.   -  person Bob Jarvis - Reinstate Monica    schedule 24.07.2013


Ответы (1)


Oracle не позволяет триггеру строки читать или изменять таблицу, для которой определен триггер. Однако, если PERSON_ID является PRIMARY или UNIQUE ключом на PERSON_INFO_TAB (что, по-видимому, имеет место, учитывая, что он используется в одноэлементном SELECT), вам действительно не нужно читать таблицу - просто используйте СТАРЫЕ или НОВЫЕ значения, где это уместно:

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 в вызове REGEXP_REPLACE. .

Делитесь и наслаждайтесь.

person Bob Jarvis - Reinstate Monica    schedule 24.07.2013
comment
Я изменил это на триггер BEFORE INSERT, чтобы соответствовать изменению вопроса OP. Я считаю, что ответ по-прежнему актуален - цитируя Оби-Вана, используйте значения :NEW, Люк!. Делитесь и наслаждайтесь. - person Bob Jarvis - Reinstate Monica; 24.07.2013
comment
Спасибо всем за вашу помощь. - person pwlm; 24.07.2013