Получить свойство переменной Oracle PL / SQl по имени (отражение в PL / SQL) - PullRequest
2 голосов
/ 14 сентября 2010

Мне нужно провести аудит при обновлении строки.

Итак, у меня есть функция, которая получает параметр типа some_table% ROWTYPE, содержащий новые значения, которые будут сохранены для этой строки.

Мне также нужно сохранить в таблице истории некоторую информацию о том, какие значения столбцов были изменены.Я думал о том, чтобы получить имена столбцов для some_table из all_tab_columns, а затем перебрать их, чтобы сравнить старые и новые значения и посмотреть, изменились ли они.Проблема в том, что когда у меня есть имя столбца, я не знаю, как получить доступ к значению в моей переменной ROWTYPE.Что-то вроде var.getProperty (columnName).

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

Также я не могу использовать триггеры, потому что старшие взлеты сказали «Нет триггеров!».(Если это действительно единственный способ, я мог бы попытаться поговорить с ними еще раз об этом).

Ответы [ 2 ]

4 голосов
/ 14 сентября 2010

Возможно, стоит выяснить, почему существует правило «без триггеров».

Есть много хороших аргументов против триггеров - особенно о включении бизнес-правил в триггеры - но протоколирование обычно считается хорошим примером для их использования.

Стоит также взглянуть на встроенный Oracleуправление версиями таблицы (которая записывает строку для каждого обновления) - это сохраняет форму истории в соответствии с текущей формой таблицы.Он не дает вам историю «что изменилось», но, вероятно, лучше делать «что изменилось» в тот момент, когда вы смотрите историю, а не добавлять стоимость на каждое обновление.

Единственный способ сделать что-то наподобие того, что вы хотите - динамический доступ к свойству% ROWTYPE, - это поместить переменную в заголовок пакета (чтобы он был общедоступен), а затем выполнить динамический PL / SQL.Вы можете инкапсулировать переменную строки, если ваш динамический блок pl / sql содержит локальную копию перед каждой проверкой.т. е. представьте это как шаблон для немедленного выполнения.

DECLARE
     lNew myTab%ROWTYPE;
     lOld myTab%ROWTYPE;
     lReturn PLS_INTEGER := 0;
BEGIN
    lNew := pStatefulPackage.NewRow;
    lOld := pStatefulPackage.OldRow;
    IF NVL(lNew.<variable>,'~') != NVL(lOld..<variable>,'~') THEN
        :lReturn := 1;
    END IF;
END;

С этим много хлопот, чтобы обойти тот факт, что вы не можете связывать переменные записи или логические значения в динамическом SQL.

Это также добавляет много накладных расходов для каждого столбца.

Наконец, я обнаружил, что ALL_TAB_COLUMNS слишком медленный, чтобы использовать его для такого рода вещей - вам нужно будет кэшировать метаданные в локальном pl /sql memory.

2 голосов
/ 14 сентября 2010

Может быть проще всего сгенерировать тело функции, прочитав имена столбцов из USER_TAB_COLUMNS, например (упрощенно, не проверяет наличие нулей):

select 'if :old.'||column_name||' <> :new.'||column_name||' then log('''||column_name||''',:old.'||column_name||',:new.'||column_name||'); end if;'
  from user_tab_columns
  where table_name='MYTABLE';
...