PL / SQL Trigger - динамическая ссылка: NEW или: OLD - PullRequest
1 голос
/ 27 марта 2009

Можно ли динамически ссылаться на: НОВЫЕ / СТАРЫЕ псевдо записи или копировать их?

Я выполняю триггер аудита для очень широкой таблицы, поэтому хотел бы избежать использования отдельных триггеров для вставки / удаления / обновления.

При обновлении / вставке я хочу записать: NEW значения в таблицу аудита, при удалении я хочу записать: OLD значения.

Ответы [ 6 ]

3 голосов
/ 30 октября 2012

создать или заменить триггер audit_tgr перед вставкой, обновлением или удалением таблицы 'name_name'

for each row
 begin
  if (inserting or updating) then
   insert into audit table (a,b,c) values(:new.a,:new.b,:new.c);
  else
   insert into audit table (a,b,c) values(:old.a,:old.b,:old.c);
end;
2 голосов
/ 27 марта 2009

ВАУ, Вы хотите, чтобы в вашем триггере была только ОДНА вставка, чтобы избежать чего?

"У меня есть один оператор вставки INSERT INTO HIST (EMP_ID, NAME) VALUES (: NEW.EMP_ID,: NEW.NAME); при удалении я хочу использовать: OLD, не иметь отдельного вставить заявление для этого. "

Это широкий стол. ТАК? В текстовых редакторах нет ЗАМЕНЫ, вы не собираетесь писать вставку снова, просто скопируйте, вставьте, выберите, замените: НОВЫЙ на: СТАРЫЙ.

У Тони есть решение, но я серьезно сомневаюсь, что оно работает лучше, чем 2 вставки.

В чем дело?


EDIT

главное, чего я пытаюсь избежать, - это управлять двумя вставками при изменении таблицы. - Мэтью Уотсон

Я постоянно сражаюсь с таким отношением. Те, кто пишет Java, C ++ или .Net, имеют встроенный RBO ... Делайте это, это хорошо. Не делай этого, это плохо. Они пишут код в соответствии с этими правилами, и это нормально. Проблема в том, что эти правила применяются к базам данных. Базы данных ведут себя не так, как код.

В мире кода иметь практически одинаковый код в двух «местах» - это плохо. Мы избегаем этого. Можно было бы абстрагировать этот код от функции и вызывать его из двух мест, чтобы избежать его повторного обслуживания, возможно, пропуская его и т. Д. Все мы знаем детали.

В этом случае, хотя true , в конце я рекомендую две вставки, они разделены ELSE. Вы не поменяете одно и не забудете другое. Это прямо там . Это не в другом пакете, или в каком-то скомпилированном коде, или даже где-то еще в том же триггере. Они находятся рядом друг с другом, есть ELSE и вставка повторяется с: NEW, а не: OLD. Почему я так без ума от этого? Это действительно имеет значение здесь? Я знаю, что две вставки не будут хуже других идей, и это может быть лучше.

Настоящая причина готовится к тем временам, когда это имеет значение. Если вы избегаете двух вставок ради технического обслуживания, вы упустите время, когда это будет ОГРОМНОЕ различие.

INSERT INTO log
SELECT * FROM myTable 
WHERE flag = 'TRUE'

ELSE                          -- column omitted for clarity

INSERT INTO log
SELECT * FROM myTable 
WHERE flag = 'FALSE'

Некоторые, включая Мэтью, сказали бы, что это плохой код, есть две вставки. Я мог бы легко заменить «ИСТИНА» и «ЛОЖЬ» переменной связывания и перевернуть ее по желанию. И это то, что сделает большинство людей. Но если True равен 0,1% значений, а 99,9% - False, вам нужны две вставки, потому что вам нужны два плана выполнения. Один лучше с индексом, а другой - FTS. Итак, да, у вас есть две вставки для обслуживания. Это не всегда плохо, и в этом случае это хорошо и желательно.

2 голосов
/ 27 марта 2009

Вы можете попробовать:

declare
  l_deleting_ind varchar2(1) := case when DELETING then 'Y' end;
begin
  insert into audit_table (col1, col2)
  values
   ( CASE WHEN l_deleting_ind = 'Y' THEN :OLD.col1 ELSE :NEW.col1 END
   , CASE WHEN l_deleting_ind = 'Y' THEN :OLD.col2 ELSE :NEW.col2 END
   );
end;

Я обнаружил, что переменная была обязательной - вы не можете получить доступ к DELETING непосредственно в операторе вставки.

1 голос
/ 27 марта 2009

Вы можете использовать составной триггер и программно проверить, использует ли он I / U / D.

Составные триггеры

0 голосов
/ 27 марта 2009

Используйте составной триггер, как предлагали другие. При необходимости сохраните старые или новые значения в переменных и используйте переменные в операторе вставки:

declare
  v_col1  table_name.col1%type;
  v_col2  table_name.col2%type;
begin
  if deleting then
    v_col1 := :old.col1;
    v_col2 := :old.col2;
  else
    v_col1 := :new.col1;
    v_col2 := :new.col2;
  end if;

  insert into audit_table(col1, col2)
  values(v_col1, v_col2);
end;
0 голосов
/ 27 марта 2009

Почему бы вам не использовать встроенный стандартный или детальный аудит Oracle?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...