Я предполагаю, что вы имеете в виду, что у вас есть триггер уровня строки, а не триггер уровня схемы. Триггер уровня схемы срабатывает, когда, например, кто-то выполняет DDL для таблицы в схеме. Нет смысла говорить о новых и старых значениях, когда вы говорите о триггере уровня схемы.
И если мы говорим о триггерах на уровне строк, я предполагаю, что вас действительно интересуют только UPDATE
операторы. Если вы вставляете или удаляете данные, вы естественным образом меняете каждый столбец в таблице.
Итак, если мы обсуждаем триггеры уровня строки, которые срабатывают на UPDATE
, вы потенциально можете использовать функцию UPDATING
. Это говорит вам, обновляется ли конкретный столбец. Однако это не обязательно означает, что данные изменяются. Заявление
UPDATE table_name
SET col1 = col1;
обновляет COL1
для каждой строки в TABLE_NAME
, но фактически не меняет никаких данных. Если это приемлемо, вы можете сделать что-то вроде
CREATE TRIGGER trg_table_name
BEFORE UPDATE ON table_name
FOR EACH ROW
BEGIN
IF( updating( 'COL1' ) )
THEN
<<col1 was updated>>
END IF;
IF( updating( 'COL2' ) )
THEN
<<col2 was updated>>
END IF;
...
END;
Вы можете сделать это немного более динамичным, просто зацикливая данные в USER_TAB_COLS
, т.е.
SQL> ed
Wrote file afiedt.buf
1 create table foo (
2 col1 number,
3 col2 number,
4 col3 number
5* )
SQL> /
Table created.
SQL> create trigger trg_foo
2 before update on foo
3 for each row
4 begin
5 for cols in (select *
6 from user_tab_cols
7 where table_name = 'FOO')
8 loop
9 if updating( cols.column_name )
10 then
11 dbms_output.put_line( 'Updated ' || cols.column_name );
12 end if;
13 end loop;
14 end;
15 /
Trigger created.
SQL> set serveroutput on;
SQL> insert into foo values( 1, 2, 3 );
1 row created.
SQL> update foo
2 set col2 = col2 + 1,
3 col3 = col3 * 2;
Updated COL2
Updated COL3
1 row updated.
Хотя это может показать вам все обновляемые столбцы, тем не менее, основным недостатком является то, что невозможно получить доступ к значениям :new
и :old
аналогичным динамическим образом. Таким образом, вы можете узнать, что COL2
было обновлено, но вы не можете определить, что было значением :new.col2
или :old.col2
, без статической ссылки на эти значения.
Потенциально, в зависимости от проблемы, которую вы пытаетесь решить, вы можете написать код, который динамически генерирует ваш триггер, просматривая данные в словаре данных. Что-то в этом блоке сгенерирует триггер для конкретной таблицы, который выводит все :new
значения
DECLARE
l_tbl_name VARCHAR2(100) := 'FOO';
l_sql_stmt VARCHAR2(4000);
BEGIN
l_sql_stmt := 'CREATE OR REPLACE TRIGGER trg_' || l_tbl_name ||
' BEFORE UPDATE ON ' || l_tbl_name ||
' FOR EACH ROW ' ||
'BEGIN ';
FOR cols IN (SELECT *
FROM user_tab_cols
WHERE table_name = l_tbl_name )
LOOP
l_sql_stmt := l_sql_stmt ||
' IF UPDATING( ''' || cols.column_name || ''' ) ' ||
' THEN ' ||
' dbms_output.put_line( :new.' || cols.column_name || '); ' ||
' END IF; ';
END LOOP;
l_sql_stmt := l_sql_stmt || ' END; ';
dbms_output.put_line( l_sql_stmt );
EXECUTE IMMEDIATE l_sql_stmt;
END;