Тригеры UPDATE в ORACLE
От: Лукья  
Дата: 29.01.02 10:33
Оценка:
Господа, может кто-нибудь подскажет как можно решить следующую проблему — выдачу Oracle исключения
при попытке сделать update на таблицу в тригере before(after) update на эту таблицу. Это нормально например
для Interbase.
Re: Тригеры UPDATE в ORACLE
От: Максимов Андрей Россия  
Дата: 29.01.02 10:44
Оценка:
Здравствуйте Лукья, Вы писали:

Л> Господа, может кто-нибудь подскажет как можно решить следующую проблему — выдачу Oracle исключения

Л>при попытке сделать update на таблицу в тригере before(after) update на эту таблицу. Это нормально например
Л>для Interbase.

raise <exception>;

или

raise_application_error(<error_code -20001..-20999>,<error_message>);
Re[2]: Тригеры UPDATE в ORACLE
От: Лукья  
Дата: 29.01.02 11:17
Оценка:
Здравствуйте Максимов Андрей, Вы писали:

МА>Здравствуйте Лукья, Вы писали:


Л>> Господа, может кто-нибудь подскажет как можно решить следующую проблему — выдачу Oracle исключения

Л>>при попытке сделать update на таблицу в тригере before(after) update на эту таблицу. Это нормально например
Л>>для Interbase.

МА>raise <exception>;


МА>или


МА>raise_application_error(<error_code -20001..-20999>,<error_message>);


Сам виноват, не так сформулировал... Мне нужно не отпихнуться от исключения, а обойти это, т.е можно-ли и как, если можно, производить UPDATE TABLE set FIELD=... where ... из тригера BEFORE UPDATE
Re[3]: Тригеры UPDATE в ORACLE
От: Максимов Андрей Россия  
Дата: 29.01.02 11:32
Оценка: -1
Здравствуйте Лукья, Вы писали:

Л>Здравствуйте Максимов Андрей, Вы писали:


МА>>Здравствуйте Лукья, Вы писали:


Л>>> Господа, может кто-нибудь подскажет как можно решить следующую проблему — выдачу Oracle исключения

Л>>>при попытке сделать update на таблицу в тригере before(after) update на эту таблицу. Это нормально например
Л>>>для Interbase.

МА>>raise <exception>;


МА>>или


МА>>raise_application_error(<error_code -20001..-20999>,<error_message>);


Л> Сам виноват, не так сформулировал... Мне нужно не отпихнуться от исключения, а обойти это, т.е можно-ли и как, если можно, производить UPDATE TABLE set FIELD=... where ... из тригера BEFORE UPDATE


Думаю, что нет...
Re[3]: Тригеры UPDATE в ORACLE
От: VVP Россия 67524421
Дата: 30.01.02 12:18
Оценка:
Здравствуйте Лукья, Вы писали:

Л> Сам виноват, не так сформулировал... Мне нужно не отпихнуться от исключения, а обойти это, т.е можно-ли и как, если можно, производить UPDATE TABLE set FIELD=... where ... из тригера BEFORE UPDATE


Ну, имхо, в большинстве случаев это свидетельствует о неправильно спроектированной БД. Кроме, пожалуй, одного случая — когда надо организовать рекурсивное дерево и устанавливать на уровни, имеющие подуровни, признак наличия подуровней. Хотя, наверное, есть еще другие примеры и я, может быть, погорячился о неправильном проектировании.

Так вот, ближе телу:
create table TREE(
  TREE_ID    NUMBER(10) default 0 not null,
  PARENT_ID  NUMBER(10) default 0,
  IS_FOLDER  CHAR(1) default 'F' not null /* только 'T','F' - допустимы */,
  NAME       VARCHAR2(80)
);

alter table TREE
  add constraint TREE_TREE_FK foreign key (PARENT_ID)
  references TREE (TREE_ID) on delete cascade;
/* хотя on delete cascade можно и пересмотреть */


Дальше пишешь триггер before for each row:
create or replace trigger TREE_REG_UPD
  BEFORE DELETE OR INSERT OR UPDATE OF PARENT_ID
  ON TREE
  FOR EACH ROW
BEGIN
  IF INSERTING OR UPDATING THEN
    PCK_TREE.REG_ID(:NEW.PARENT_ID);
  END IF;
  IF DELETING OR UPDATING THEN
    PCK_TREE.REG_ID(:OLD.PARENT_ID);
  END IF;
END;


И триггер уровня statement:
create or replace trigger TREE_SET_FOLDER
  AFTER DELETE OR INSERT OR UPDATE
  ON TREE
BEGIN
  PCK_TREE.SET_FOLDER;
END;


Теперь осталось рассмотреть пакет, в данные которого ты регистрируешь изменяемые записи и который обновляет эти записи через SET_FOLDER:
CREATE OR REPLACE PACKAGE PCK_TREE IS
  PROCEDURE REG_ID(P_ID IN NUMBER := 0);
  PROCEDURE SET_FOLDER;
END PCK_TREE;

CREATE OR REPLACE PACKAGE BODY PCK_TREE IS

TYPE TTBL_ID IS TABLE OF NUMBER(10,0) INDEX BY BINARY_INTEGER;
V_RECURSED BOOLEAN := FALSE;
V_TABLE_ID TTBL_ID;

PROCEDURE REG_ID(P_ID IN NUMBER := 0) IS
BEGIN
  IF P_ID IS NOT NULL THEN
    V_TABLE_ID(P_ID) := P_ID;
  END IF;
END;

PROCEDURE SET_FOLDER IS
  V_COUNT NUMBER;
  V_INDEX BINARY_INTEGER;
BEGIN
  IF NOT V_RECURSED THEN
    V_RECURSED := TRUE;
    IF V_TABLE_ID.COUNT > 0 THEN
      V_INDEX :=  V_TABLE_ID.FIRST;
      LOOP
        SELECT COUNT(*) INTO V_COUNT
          FROM TREE WHERE PARENT_ID=V_TABLE_ID(V_INDEX) AND ROWNUM<2;
        UPDATE TREE SET IS_FOLDER = DECODE(V_COUNT, 0, 'F', 'T')
          WHERE TREE_ID=V_TABLE_ID(V_INDEX);
      EXIT WHEN V_INDEX = V_TABLE_ID.LAST;
        V_INDEX := V_TABLE_ID.NEXT(V_INDEX);
      END LOOP;
      V_TABLE_ID.DELETE;
    END IF;
    V_RECURSED := FALSE;
  END IF;
END;

END PCK_TREE;


Про признак рекурсивности не забудь — это достаточно важно.

Идеология самого оракла такова — операторы DML над таблицей, владелицей триггера, в триггерах уровня ROW для такой таблицы запрещены, поскольку ведут к рекурсивному вызову триггеров — что небезопасно. Но в триггерах уровня STATEMENT операции DML над таблицей-владелицей разрешены.
Никогда не бойся браться делать то, что делать не умеешь. Помни, ковчег был построен любителем. Профессионалы построили Титаник...
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.