Как распознать измененные значения в триггере схемы? - PullRequest
1 голос
/ 17 марта 2012

Может кто-нибудь сказать мне, как найти некоторые различия между новыми и старыми значениями в триггере схемы?Триггер работает на INSERT, UPDATE, DELETE.Я знаю, что trgigger может использовать :old.* и :new.*

Ответы [ 2 ]

4 голосов
/ 18 марта 2012

Я предполагаю, что вы имеете в виду, что у вас есть триггер уровня строки, а не триггер уровня схемы. Триггер уровня схемы срабатывает, когда, например, кто-то выполняет 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;
2 голосов
/ 18 марта 2012
          :old            :new
=======================================================
insert | null         |    new value to be inserted
update | old value    |    new value to be updated
delete | old value    |    null
=======================================================

Приведенные выше значения относятся к триггерам уровня строки, что означает, что триггер срабатывает каждый раз для каждой строки.

В приведенной выше таблице показано значение new old по отношению к приведенным выше инструкциям dml, давайте рассмотрим пример.

Insert into abc (1,'gaurav soni',pune);--empid,name,city

Предположим, у меня есть триггер на таблицу abc, который при вставке в таблицу abc проверяет, присутствует ли город в таблице местоположений или нет (я знаю, что мы можем сделать это с ограничением внешнего ключа), но это пример, поэтому мы можем укажите город как :new.city, но мы не можем указать :old .city в случае вставки, поскольку его значение равно null.

В случае update мы можем ссылаться как :new and :old value

В случае delete мы можем ссылаться только на old value, поскольку new value равно null в случае deleting.

Примечание : использование :new в случае delete, :old в случае inserting не даст вам compile time error, но, несомненно, будет бум и даст вам run time error Вы можете использовать предложение INSERTING,DELETING, чтобы избежать этого.

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