2015-05-26 1 views
0

Я имею базу данных Oracle с следующий сценарий (упрощенный):Oracle Trigger - имя таблицы мутирует, триггер/функция может не видеть, что это

Projects      Params 
-------------     ----------- 
PROJ_ID  SCODE    PARAM_ID PARAM_TYPE PROJ_ID PARAM_VALUE 
1000  123    5000  4614  1000 '00' 
1001  124    5001  4610  1000 'Micro' 
1002  123    5002  4614  1001 '02' 
           5003  4614  1002 '01' 

Это означает, что 3 Проекты - Проект 1000 имеет 2 различных параметров а второй и третий проекты имеют по одному параметру.

Теперь мне нужно написать триггер в таблице проектов, который автоматически вставляет новую строку в таблицу params с максимальным значением +1 параметра с типом «4614» с данным SCODE.

INSERT INTO Projects VALUES (1003,123) 

... должно вызвать событие

INSERT INTO Parameters VALUES (5004,4614,1003,'02') 

Теперь у меня есть 2 возможности, и оба не работают:

Если триггер объявлен как «ДО», я не могу вставить в таблице «Параметры», потому что ограничение внешнего ключа показывает мне ошибку, что Project 1003 еще не создан. Выполнение Commit внутри триггера невозможно.

Если триггер объявлен как «после», я получаю сообщение об ошибке

ORA-04091: table name is mutating, trigger/function may not see it 

, потому что я доступ к таблице, которая срабатывает прямо сейчас.

Должно быть какое-либо решение этой проблемы. Любая помощь приветствуется!

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

Мой Trigger:

CREATE OR REPLACE TRIGGER PROJ_ARI_TRIGGER 
AFTER INSERT 
ON PROJECTS 
REFERENCING NEW AS NEW OLD AS OLD 
FOR EACH ROW 
DECLARE 
v_param VARCHAR2(10); 
BEGIN 
     v_param := get_next_param_val(:new.SCODE); 
     INSERT INTO Parameters(<<sequence>>,4614,:new.PROJ_ID,v_param); 
END PROJ_ARI_TRIGGER; 

Функция get_next_param_val просто делает выбор таблицы проектов и возвращает правильное значение параметра.

+1

Вы можете изменить внешний ключ, так что откладываемые; таким образом, он не будет проверяться, пока вы не зафиксируете. Имейте в виду, что это может вызвать проблемы, если вы делаете массовые обновления - вы не получите ошибок до самого конца транзакции. В качестве альтернативы вместо того, чтобы вставлять непосредственно в таблицу, выполните ее с помощью хранимой процедуры. Таким образом, вы можете правильно управлять логикой и потоком, не выполняя причудливые обходные пути. – Boneist

+0

@Boneist К сожалению, я не могу изменить ограничение системы баз данных. Зачем ставить заявление INSERT в хранимую процедуру? Содержимое триггера запуска похоже на v_new_param: = calculate_param(); вставьте значения параметров (...., new.proj_id, v_new_param). –

+0

было бы лучше, если бы вы отредактировали свой вопрос, чтобы добавить скрипт для создания триггера. – Boneist

ответ

0

Darned mutating tables! Время для пакета.

CREATE OR REPLACE PACKAGE no_mutation_pkg 
AS 
    procedure set_val(pVal number); 
    function get_val return number; 
END; 
/

CREATE OR REPLACE PACKAGE BODY no_mutation_pkg 
AS 
    g_val number; 
    procedure set_val(pVal number) 
    IS 
    BEGIN 
     g_val := pVAl; 
    END; 
    function get_val return number 
    IS BEGIN 
     return g_val; 
    end; 
    END; 

А потом создать ДО вставить триггер, который вычисляет значение и сохраняет его в пакете с set_val, а триггер AFTER вставки извлекает значение с GET_VAL и делает вставку.

РЕДАКТИРОВАТЬ: Комментарий от Justin по дубликатам, вам обязательно нужно это учитывать. Честно говоря, архитектура данных, как правило, подозревается, когда вам нужно перепрыгнуть через такие обручи.

+0

Триггер 'after' должен быть' statement'-level. – GriffeyDog

+0

хорошо catch. Благодаря! Сегодня я набираю «на лету», поскольку я далеко от офиса. –

0

Я нашел решение для своей проблемы!

Используя соединение триггера, можно сначала получить максимальное значение в SCODE и вычислить значение пар (с перед каждой строкой)

, а затем вставить значение в таблице пар (с после каждого строка)

Детали: Compound Trigger Example

Спасибо @Bob Джарвис

+0

Замечание Пер Джастина выше, если это многопользовательская система, которую вы можете протестировать, чтобы убедиться, что вы не получите дубликатов, если два человека выполняют аналогичную вставку. например для набора данных, приведенного выше, один человек вставляет проект 1003 со скобкой 123, затем имеет другой проект 1004 вставки с scode 123, а затем оба выполняют свою фиксацию. –

Смежные вопросы