К какому типу данных относятся переменные: OLD и: NEW в триггере? - PullRequest
6 голосов
/ 10 мая 2011

Предположим, у вас есть триггер на MY_CUSTOMER_TABLE и что у него есть переменная, объявленная типа MY_CUSTOMER_TABLE%ROWTYPE. Как я могу присвоить значение OLD этой переменной?

CREATE TRIGGER CUSTOMER_BEFORE
  BEFORE UPDATE ON MY_CUSTOMER_TABLE
  FOR EACH ROW
DECLARE
  old_version MY_CUSTOMER_TABLE%ROWTYPE;
BEGIN
  old_version := :OLD; /* Causes a PLS-00049 bad bind variable 'OLD' */
  old_version := OLD;  /* Causes a PLS-00201 identifier 'OLD' must be declared */
END;

Редактировать:

Для пояснения, это произошло потому, что я использую триггеры для архивирования строк из MY_CUSTOMER_TABLE в MY_CUSTOMER_TABLE_HISTORY. В зависимости от выполняемого действия (INSERT, UPDATE, DELETE) мне могут понадобиться все поля из OLD или NEW:

CREATE TRIGGER CUSTOMER_BEFORE
  BEFORE UPDATE ON MY_CUSTOMER_TABLE
  FOR EACH ROW
DECLARE
  historical_record MY_CUSTOMER_TABLE_HISTORY%ROWTYPE;

  PROCEDURE
    copy
    (
      source_record      MY_CUSTOMER_TABLE%ROWTYPE,
      destination_record IN OUT MY_CUSTOMER_TABLE_HISTORY%ROWTYPE
    )
  BEGIN
    destination_record.customer_id   := source_record.customer_id;
    destination_record.first_name    := source_record.first_name;
    destination_record.last_name     := source_record.last_name;
    destination_record.date_of_birth := source_record.date_of_birth;
  END;

BEGIN
  /* I didn't want to replicate the same assignment statements for 
     each of the two cases: */
  CASE
    WHEN INSERT OR UPDATING THEN
      copy( source_record => :NEW, destination_record => historical_record );

    WHEN DELETING THEN
      copy( source_record => :OLD, destination_record => historical_record );

  END CASE;

  /* Some other assignments to historical_record fields... */

  INSERT INTO MY_CUSTOMER_TABLE_HISTORY VALUES historical_record;
END;

В этом сценарии PL / SQL не позволит мне передать :OLD или :NEW процедуре, которая ожидает аргумент MY_CUSTOMER_TABLE%ROWTYPE.

Ответы [ 3 ]

4 голосов
/ 10 мая 2011

Вы не можете.Обычно плохая практика - ссылаться на все столбцы (например, SELECT *), и вы должны указать нужные столбцы.

2 голосов
/ 10 мая 2011

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

trigger ....
  l_row  mytable%rowtype;
begin
  l_row.column1 := :old.column1;
  l_row.column2 := :old.column2;
  ...

  archive_function(l_row);
end;
1 голос
/ 10 мая 2011

Из того, что я могу определить, определение того, что: NEW и: OLD действительно немного размыто. Я видел, что это упоминается как ссылка на «псевдо-запись». Казалось бы, однако, что вместо фактического типа строки с возможностью ссылки на каждый столбец в типе строки Oracle устанавливает ссылку на каждый отдельный столбец, на который вы затем ссылаетесь, используя: NEW и: OLD. Но, как вы выяснили,: NEW и: OLD, похоже, сами по себе не справляются.

Например, здесь . (да, да, я знаю, это ссылка на Java, но см. комментарий о том, что OLD сама по себе не является допустимой ссылкой.

Я также нашел этот пакет примечаний SYS.DBMS_DEBUG, который подразумевает, что: NEW /: OLD также не является действительным связыванием.

- get_value и set_value теперь поддерживают имена привязок. Связанные имена должны быть - ставить в кавычки и использовать заглавные буквы. Обратите внимание, что триггерные привязки имеют - квалифицированные имена, то есть ": NEW" не является действительной связью, тогда как ": NEW.CLMN" - действует.

Будет ли этим предложением использовать AFTER триггер для вас? Из вашего примера не похоже, что для значений происходит какая-либо проверка (понимая, что вы, возможно, не включили это в свой пример для простоты).

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

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