2015-01-28 3 views
0

Я делаю небольшой проект для своего предмета в университете, и у меня возникла проблема с проектированием триггера в Oracle SQL Developer для моей небольшой базы данных.Oracle SQL Developer Мутирующие таблицы и триггеры

У меня есть следующие таблицы:

create table ASSIGNED_TO(
    ASSIGNMENT_ID int not null primary key, 
    ROOM_ID int not null, 
    foreign key (ROOM_ID) references ROOM(ROOM_ID), 
    NURSE_ID int not null, 
    foreign key (NURSE_ID) references NURSE(PERSON_ID) 
); 

create table MESSAGE_LOG(
    ID int not null, 
    MESSAGE varchar2(100) null 
); 

Каждый раз, когда строка из таблицы ASSIGNED_TO изменяется INSERT или UPDATE операции и есть 2 строки с тем же ROOM_ID Я хочу триггер, чтобы написать простое сообщение в стол MESSAGE_LOG.

Что вызывает у меня проблемы - это «мутация» таблицы ASSIGNED_TO. Мое текущее решение:

create or replace TRIGGER TRIG3 
    AFTER INSERT OR UPDATE 
    ON ASSIGNED_TO 
    FOR EACH ROW 
DECLARE 
    nr_nurses INTEGER; 
BEGIN 
     SELECT COUNT(*) INTO nr_nurses 
     FROM ASSIGNED_TO 
     WHERE ROOM_ID = :NEW.ROOM_ID; 

     IF nr_nurses >= 2 THEN 
     INSERT INTO MESSAGE_LOG values (3, '2 or more nurses per room detected'); 
     DBMS_OUTPUT.PUT_LINE('3| 2 or more nurses per room detected'); 
     END IF; 
END; 

Этот триггер дает мне ошибку «мутирует Table» и до сих пор я не смог это исправить. Использование :OLD.ROOM_ID вместо ROOM_ID не работает, поскольку :OLD.ROOM_ID не существует в случае UPDATE операции. Любые советы по выполнению этой работы приветствуются.

ответ

3

Как отметил @MichaelBroughton, вы не можете использовать триггер строки, поскольку вы получите исключение «мутирующих таблиц». Существуют различные способы решения этой проблемы; возможно, самым простым является использование триггера оператора для достижения той же цели. Доработка триггер как:

CREATE OR REPLACE TRIGGER TRIG3 
    AFTER INSERT OR UPDATE 
    ON ASSIGNED_TO 
BEGIN 
    -- The following cursor will only find rows for 
    -- which multiple nurses have been assigned. 

    FOR aRow IN (SELECT ROOM_ID, COUNT(*) AS NURSE_COUNT 
       FROM ASSIGNED_TO 
       GROUP BY ROOM_ID 
       HAVING COUNT(*) >= 2) 
    LOOP 
    INSERT INTO MESSAGE_LOG 
     (ID, MESSAGE) 
    VALUES 
     (3, aRow.NURSE_COUNT || 'ASSIGNED TO ROOM ' || aRow.ROOM_ID); 

    DBMS_OUTPUT.PUT_LINE('3| ' || aRow.NURSE_COUNT || 'ASSIGNED TO ROOM ' || 
         aRow.ROOM_ID); 
    END LOOP; 
END TRIG3; 

Примечание: это триггер заявление, потому что он не включает в себя линию FOR EACH ROW.

Этот триггер будет вызываться один раз для каждого оператора INSERT или UPDATE, который влияет на таблицу ASSIGNED_TO вместо одного раза для каждой строки, измененной, но таким образом триггер будет обеспечивать ту же функциональность, что и исходный триггер строки, и не будет страдать от проблема «мутирующего стола».

Делитесь и наслаждайтесь.

+0

Да, хотя это просто вызывает новые проблемы, например, в этом случае все предыдущие вставки, вызвавшие это условие, были бы повторно найдены и перезаписаны на каждую вставку или обновление в таблицу, поэтому вам нужно будет добавить проверку против message_log, чтобы вы не повторяли повтор одной и той же проблемы снова и снова. И использование триггера уровня инструкций для операций на уровне строк просто неэффективно, как черт! Не сказать, что это не сработает. Но плохой стиль программирования для начала, если его можно избежать. –

+0

Моя цель - использовать триггер, и я понимаю плюсы и минусы этого решения. Этот код работает для моей цели. Благодаря! – Quass1m

1

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

Ответ заключается в том, чтобы не выполнять эту проверку через триггер. Я предпочитаю, чтобы интерфейсы бизнес-уровня pl/sql были доступны, а не чистое взаимодействие таблицы с пользовательским интерфейсом. Например, введите код insert_room_assigment (nurse_id, room_id), который выполняет вставку, проверку и журналы, если это необходимо, или может проверить сначала, и не разрешить вставку в первую очередь.

Но, как бы вы ни решили, триггер НЕ будет работать.

+0

Это действительно приятно слышать, так как я могу сосредоточить свое внимание на вещах, которые могут работать. Спасибо. – Quass1m

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