2009-05-26 3 views
4

Как я могу обойти ограничения Oracle, не позволяющие подзапросы в триггерах.Oracle: Использование подзапроса в триггере

Вот пример триггера, который я пытаюсь создать, но не могу, потому что я не могу использовать подзапрос.

CREATE OR REPLACE TRIGGER trigger_w_subquery 
AFTER UPDATE OR INSERT ON project_archiving 
FOR EACH ROW WHEN (old.archiving_status <> new.archiving_status 
    AND new.archiving_status = 1 
    AND (SELECT offer FROM projects WHERE projnum = :new.projnum) IS NULL 
) 
BEGIN 
    INSERT INTO offer_log (offer, status, date) 
    VALUES (null, 9, sysdate); 
END; 

ответ

9

Этот триггер будет делать это:

CREATE OR REPLACE TRIGGER trigger_w_subquery 
AFTER UPDATE OR INSERT ON project_archiving 
FOR EACH ROW WHEN (old.archiving_status <> new.archiving_status 
    AND new.archiving_status = 1 
) 
DECLARE 
    l_offer projects.offer%TYPE; 
BEGIN 
    SELECT offer INTO l_offer 
    FROM projects 
    WHERE projnum = :new.projnum; 

    IF l_offer IS NULL THEN 
    INSERT INTO offer_log (offer, status, date) 
    VALUES (null, 9, sysdate); 
    END IF; 
END; 

Я предположил, что выбор из проектов всегда найдет строку; если это не приведет к возникновению исключения NO_DATA_FOUND, которое вам может потребоваться.

+2

Отличные мысли думают одинаково :-) –

+1

Просто предупреждение о том, что если вы используете вставки из нескольких таблиц (вставляя как в проект, так и в project_archiving), вы можете столкнуться с ошибкой мутирующей таблицы. Таким образом, предпочтительнее поставить логику, где находится исходная вставка, а не полагаться на триггер. –

2

Вы можете поставить условие в действие (между НАЧАТЬ и END) вместо того, чтобы в "выстреливает ли это? Да, это означает, что тело триггера может быть уволен чаще - но если он получает вас вокруг проблемы ...

+3

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

+0

Попытка BEGIN IF (предложение SELECT FROM projects WHERE projnum =: new.projnum) IS NULL THEN INSERT INTO и т. Д. Однако он выдает ошибку, поскольку встречается с SELECT в этом выражении. Он просто этого не ожидает. – vipirtti

+0

Я недостаточно знаком с PL/SQL, чтобы узнать, является ли это правдоподобным способом написания кода в триггере. Выглядит хорошо; другие системы, которые, как я знаю, потребуют определенного назначения из SELECT (с предложением INTO и переменной), а затем проверяют переменную или что-то в этом направлении. Вероятно, есть описание ограничений на триггеры в руководствах. Также - можете ли вы вызвать процедуру в части действия? Если да, может, это сработает для вас? (Передайте соответствующие значения в качестве параметров.) –

4

Я ожидаю, что вы хотите что-то вроде

CREATE OR REPLACE TRIGGER trigger_w_subquery 
AFTER UPDATE OR INSERT ON project_archiving 
FOR EACH ROW 
WHEN (old.archiving_status <> new.archiving_status 
    AND new.archiving_status = 1) 
DECLARE 
    l_offer projects.offer%TYPE; 
BEGIN 
    SELECT offer 
    INTO l_offer 
    FROM projects 
    WHERE projnum = :new.projnum; 

    IF(l_offer IS NULL) 
    THEN 
    INSERT INTO offer_log (offer, status, date) 
     VALUES (null, 9, sysdate); 
    END IF; 
END; 
+0

Извините, Джастин. Я могу выбрать только один ответ как один из них. На этот раз вы были избиты простым предупреждением об исключении :-) Голос, которого вы заслужили, тем не менее. – vipirtti

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