Конфликтующие триггеры в базе данных Oracle - PullRequest
1 голос
/ 08 апреля 2011

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

  • department(alpha, college, etc.)
  • course(id, alpha, college, title, etc.)

Колледж и альфа представлены в обеих таблицах по дизайну. Я решил немного отменить нормализацию, потому что колледж и альфа всегда желательны при просмотре курса.

У меня есть один триггер, который выполняется после обновления таблицы department, так что он обновляет все строки в таблице course новыми значениями alpha и college. У меня также есть триггер, который выполняется перед обновлением таблицы course, чтобы убедиться, что пара alpha - college, которую пользователь отправил в своих изменениях, существует в таблице department; если пары нет, то возникает ошибка приложения.

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

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

Ответы [ 4 ]

3 голосов
/ 08 апреля 2011

Ваш второй триггер звучит как не что иное, как внешний ключ. Удалите его и создайте ограничение внешнего ключа для course. Это работает в моих тестах.

Тем не менее, кажется ненужной работой поддерживать денормализацию, которая дает мало пользы. Если вы просто хотите написать простые запросы, создайте представление, объединяющее две таблицы, и используйте его в своих запросах. Если вас беспокоит производительность соединения, я очень сомневаюсь, что это будет проблемой, если вы не пропустите очевидные индексы в таблицах.

2 голосов
/ 08 апреля 2011

Как и в большинстве других случаев, реализованных с помощью триггеров, вы можете увидеть здесь нагрузку, потому что сама модель данных имеет дефекты.

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

---Department references College...

Create table department(
   department_id number primary key,
   aplha varchar2(20) not null,
   college varchar2(20) not null
);

***--Course belongs to a department.. so should be a child of department.
--If it's possible for different depts to give the same course (IT and CS), 
--you'll have 
--a dept_course_asc table***

Create table Course(
    course_id number primary key
    department_id number references department(department_id),
    course_name varchar2(100) not null
);

если у вас есть таблица ученика, вы свяжете ее с таблицей курса сеще одна таблица связей студента-таблицы.

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

2 голосов
/ 08 апреля 2011

Я бы искренне рекомендовал удалить ваш триггерный подход все вместе, так как он обременен грязным чтением. Всякий раз, когда я сталкивался с такой проблемой, я реализовывал DML, используя только хранимые процедуры. При правильной реализации вы получаете все преимущества триггеров без головной боли.

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

Всего $ 0,02

0 голосов
/ 08 апреля 2011

Существует два возможных решения проблемы.

Решение 1: Использование ограничения DEFERRABLE FK.

Это решение возможно только при комбинации (альфа, колледж)является уникальным и может быть определен как PK для таблицы отдела.В этом случае вам не нужен триггер для таблицы курса.

Вместо этого вы определяете DEFERRABLE FK (альфа, колледж) для курса, который ссылается на таблицу факультетов.

И додля обновления в отделе необходимо выполнить инструкцию SET CONSTRAINT ... DEFERRED см. документацию .Тогда FK не будет проверен до фиксации.

Решение 2. Использование системного контекста

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

Контекст должен быть создан первым. см. Пользовательские контексты

Триггер в отделе устанавливает переменную в контексте на некоторое значение.

И во втором триггере на курсах вы проверяете значениепеременная в контексте

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