PL/SQL Trigger - динамическая ссылка: NEW или: OLD

58
7

Можно ли динамически ссылаться на: NEW/OLD псевдозаписи или скопировать их?


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


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

спросил(а) 2009-03-27T02:00:00+03:00 11 лет, 7 месяцев назад
1
Решение
81

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


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;

ответил(а) 2009-03-27T22:38:00+03:00 11 лет, 7 месяцев назад
81

создать или заменить триггер audit_tgr
перед вставкой или обновлением или удалением в 'table_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;

ответил(а) 2012-10-30T19:16:00+04:00 7 лет, 12 месяцев назад
71

WOW, вы хотите, чтобы в вашем триггере только одна вставка, чтобы избежать чего?


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


Это широкая таблица. ТАК? Это не так, как там нет REPLACE в текстовых редакторах, вы больше не будете писать Insert, просто скопируйте, вставьте, выберите, замените: NEW: OLD.


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


Какая большая сделка?


ИЗМЕНИТЬ


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


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


В мире кода, по существу, тот же код в двух "местах" плох. Мы избегаем этого. Можно было бы отвлечь этот код от функции и вызвать его из двух мест и, таким образом, не поддерживать его дважды и, возможно, отсутствовать и т.д. Мы все знаем, что происходит.


В этом случае, хотя это правда, что в конце я рекомендую две вставки, они разделены ELSE. Вы не измените его и не забудете другого. IT Right There. Это не в другом пакете, или в некотором скомпилированном коде, или даже где-то еще в одном и том же триггере. Они находятся рядом друг с другом, там ELSE, а Insert повторяется с: 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" и "FALSE" на переменную bind и перевернуть ее по своему усмотрению. И это то, что сделает большинство людей. Но если True равен .1% от значений и 99.9% - False, вы хотите две вставки, потому что вам нужны два плана выполнения. Один лучше с индексом, а другой - с FTS. Итак, да, у вас есть два вставки для поддержки. Это не всегда плохо, и в этом случае это хорошо и желательно.

ответил(а) 2009-03-27T22:05:00+03:00 11 лет, 7 месяцев назад
71

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


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 непосредственно в инструкции insert.

ответил(а) 2009-03-27T14:01:00+03:00 11 лет, 7 месяцев назад
59

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


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

ответил(а) 2009-03-27T03:22:00+03:00 11 лет, 7 месяцев назад
42

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

ответил(а) 2009-03-27T03:05:00+03:00 11 лет, 7 месяцев назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема