-
Доброго дня! Есть программа, которая выполняет в одной транзакции delete, insert, update. Есть триггер:
create or replace trigger SAMPLE_AUD before insert or delete or update on SAMPLE_TABLE for each row
, задача которого отловить все изменения и записать в таблицу аудита. Проблема в том, что отлавливается только insert. Можно ли сделать так, чтобы триггер отрабатывал на каждую команду в транзакции?
-
А все действия на одной таблице производятся?
-
да
-
должно работать.. А что за версия?
на моей, покоцанной/бесплатной работает и инсерт и апдейт
> create or replace trigger SAMPLE_AUD > before insert or delete or update on SAMPLE_TABLE > for each row
BEGIN INSERT INTO audit VALUES (:old.name, :new.name) END
-
> [2] Гость (03.02.10 10:50)
А можно сам тригер увидеть?
-
create or replace trigger INASTRBUD_AUD
before insert or delete or update on INASTRBUD
for each row
declare
New_Idaud xx_audit.INASTRBUD_AUD.IDAUD%TYPE;
begin
SELECT SEQ_INASTRBUD_AUD.NEXTVAL INTO New_Idaud FROM Dual;
IF Updating THEN
IF :old.IDNTYPBUDG <> :new.IDNTYPBUDG OR :old.IDNBACC <> :new.IDNBACC OR
:old.IDNBUDGET <> :new.IDNBUDGET OR
:old.IDINASTRBUD <> :new.IDINASTRBUD THEN
INSERT INTO xx_audit.INASTRBUD_AUD
(IDNTYPBUDG,
IDNBACC,
IDNBUDGET,
IDINASTRBUD,
IDAUD,
DML_TYPE,
DML_TYPEU,
TERMINAL,
OS_USER,
IP_ADRES,
SESSION_USER)
VALUES
(:old.IDNTYPBUDG,
:old.IDNBACC,
:old.IDNBUDGET,
:old.IDINASTRBUD,
New_Idaud,
'U',
'0',
TRIM(Sys_Context('userenv', 'TERMINAL')),
TRIM(Sys_Context('userenv', 'OS_USER')),
TRIM(Sys_Context('userenv', 'IP_ADDRESS')),
TRIM(Sys_Context('userenv', 'SESSION_USER')));
INSERT INTO xx_audit.INASTRBUD_AUD
(IDNTYPBUDG,
IDNBACC,
IDNBUDGET,
IDINASTRBUD,
IDAUD,
DML_TYPE,
DML_TYPEU,
TERMINAL,
OS_USER,
IP_ADRES,
SESSION_USER)
VALUES
(:new.IDNTYPBUDG,
:new.IDNBACC,
:new.IDNBUDGET,
:new.IDINASTRBUD,
New_Idaud,
'U',
'1',
TRIM(Sys_Context('userenv', 'TERMINAL')),
TRIM(Sys_Context('userenv', 'OS_USER')),
TRIM(Sys_Context('userenv', 'IP_ADDRESS')),
TRIM(Sys_Context('userenv', 'SESSION_USER')));
END IF;
ELSIF Inserting THEN
INSERT INTO xx_audit.INASTRBUD_AUD
(IDNTYPBUDG,
IDNBACC,
IDNBUDGET,
IDINASTRBUD,
IDAUD,
DML_TYPE,
DML_TYPEU,
TERMINAL,
OS_USER,
IP_ADRES,
SESSION_USER)
VALUES
(:new.IDNTYPBUDG,
:new.IDNBACC,
:new.IDNBUDGET,
:new.IDINASTRBUD,
New_Idaud,
'I',
'',
TRIM(Sys_Context('userenv', 'TERMINAL')),
TRIM(Sys_Context('userenv', 'OS_USER')),
TRIM(Sys_Context('userenv', 'IP_ADDRESS')),
TRIM(Sys_Context('userenv', 'SESSION_USER')));
ELSE
INSERT INTO xx_audit.INASTRBUD_AUD
(IDNTYPBUDG,
IDNBACC,
IDNBUDGET,
IDINASTRBUD,
IDAUD,
DML_TYPE,
DML_TYPEU,
TERMINAL,
OS_USER,
IP_ADRES,
SESSION_USER)
VALUES
(:old.IDNTYPBUDG,
:old.IDNBACC,
:old.IDNBUDGET,
:old.IDINASTRBUD,
New_Idaud,
'D',
'',
TRIM(Sys_Context('userenv', 'TERMINAL')),
TRIM(Sys_Context('userenv', 'OS_USER')),
TRIM(Sys_Context('userenv', 'IP_ADDRESS')),
TRIM(Sys_Context('userenv', 'SESSION_USER')));
END IF;
end INASTRBUD_AUD;
-
> [5] Гость (03.02.10 10:56) на первый взгляд вроде все логично. А если сделать три отдельных тригера на каждое действие?
-
пробовал, отрабатывает один, по последней команде
-
триггеры аудита обычно вешают на after а конкретно по теме: тест-кейс из sqlplus в студию, пожалуйста
-
Спасибо, все решилось! Дело было в ошибке сравнения с NULL. Надо так: IF Updating THEN
IF nvl(:old.IDNTYPBUDG, 0) <> nvl(:new.IDNTYPBUDG, 0) OR
nvl(:old.IDNBACC, 0) <> nvl(:new.IDNBACC, 0) OR
nvl(:old.IDNBUDGET, 0) <> nvl(:new.IDNBUDGET, 0) OR
nvl(:old.IDINASTRBUD, 0) <> nvl(:new.IDINASTRBUD, 0) THEN
-
> [9] Гость (03.02.10 15:24)
А как это влияло на НЕсрабатывании на удаление? Или ты не удалял?
-
А как в Oracle Update работает? У меня складывается глубокое убеждение, что в MSSQL он "в кишках" как delete-insert работает.
-
> Ega23 (03.02.2010 15:55:11) [11]
Update по сути такой и есть, а внутреннея реализация не интересна.
-
Гость (03.02.10 15:24) [9] null = 0 с такой логикой далеко не уедешь также, не ясно, зачем при update плодить две записи и почему в логе нет timestamp? допустим, двойной вставкой при update страхуетесь от того, что два пользователя одновременно редактируют запись(а Вам, видимо, хочется видеть что менял пользователь и на что, на случай lost update), но как Вы собираетесь определять очередность изменений при таком подходе - совершенно непонятно trim, опять же, где нужно и где не нужно
и принято сообщать, СУБД и версию удачи)
-
> null = 0 > с такой логикой далеко не уедешь
Да ничего страшного вообще то
> также, не ясно, зачем при update плодить две записи
Вполне нормально. Старое и новое значение.
> но как Вы собираетесь определять очередность изменений при > таком подходе
SELECT SEQ_INASTRBUD_AUD.NEXTVAL INTO New_Idaud FROM Dual;
Короче, вполне себе так нормальный триггер. Я бы еще поле для sysdate добавил - не помешает.
И стандартная ошибка при сравнении (забыли про null). Я так тоже люблю косячить. Правда, в последнее время уже очень редко.
-
Насчет аудита я скажу так. Я бы трижды подумал на тему - а нужен ли он такой. Пробовал несколько раз делать такое - очень скоро аудитные таблицы начинают превосходить исходные по объему на порядки. При этом используется он ОЧЕНЬ (обычно) редко и не дает особо ничего. Ну нашли виновника, и что? "Ну ошибся я, с кем не бывает". И ВСЕ. Я бы просто добавил логин юзера и дату последней модификации записи в основную таблицу. В 99% случаев этогшо достаточно.
Разумеется в некоторых системах аудит необходим даже по закону, но обычно люди пишущие его не задают вопросов на форумах.
ИМХО
ЗЫ: Я так и не понял как влияло некорректное сравнение с нулом на секцию тригера про удаление.
-
Плюсом про аудит. В Оракле (насколько я понял это он) вроде как есть штатное средство по работе со штатными логами. Log Miner вроде называется. Я с ним не разбирался, но вроде как по отзывам вполне работоспособен. А логах оракла есть все.
-
>ANB (04.02.10 12:30) [14] >Да ничего страшного вообще то 0!=null - логическая ошибка т.о. при изменении 0 на null и обратно, изменение не будет учтено
>Вполне нормально. Старое и новое значение. вопрос был "зачем" если бездумно плодить данные - нормально, то остается только умыть руки
>SELECT SEQ_INASTRBUD_AUD.NEXTVAL INTO New_Idaud FROM Dual; т.е. если ID2 > ID1, то изменения в ID2 - более поздние, так?
>Короче, вполне себе так нормальный триггер. Я бы еще поле для sysdate добавил - не помешает. timestamp и, желательно, с local time zone впрочем, это уже излишество, но весьма полезное время от времени
-
>Sergey13 © (04.02.10 13:20) [16] logminer пишет IP пользователя?)
а если серьезно, то, например, на простенькой, некритичной базке с 3-5 таблиц никто не будет поднимать архивлоги - это просто ни к чему
да и с помощью sql работать куда как приятнее - опять же можно в софтину клиентскую привязать показ изменений
-
>Sergey13 © (04.02.10 13:14) [15] перечитал Ваш пост внимательно)
>Разумеется в некоторых системах аудит необходим даже по закону, но >обычно люди пишущие его не задают вопросов на форумах. ещё как задают)) здесь ещё немного кода и специфичных названий полей/таблиц - есть примеры, когда выкладывают код в несколько десятков килобайт... только когда(и если) работодатель видит потроха базы и кода в форуме - ни к чему хорошему для вопрошавшего это не приводит
|