Если вы возьмете (естественное) СОЕДИНЕНИЕ ЖИВОТНЫХ и PREFERRED_FOOD, вы получите таблицу, в которой для каждого животного указаны его тип и предпочтительная пища.
Вы хотите, чтобы эта комбинация была «действительной» для каждого отдельного животного, где «действительный» означает «появиться в перечне допустимых комбинаций типа животного / типа корма, перечисленных в FOOD.
Итак, у вас есть ограничение, которое несколько похоже на FK, но на этот раз «внешний ключ» появляется не в базовой таблице, а в соединении двух таблиц. Для этого типа ограничения в языке SQL есть ограничения CHECK и ASSERTIONS.
Версия ASSERTION самая простая. Это ограничение вроде (я был несколько либерален с именами атрибутов, чтобы избежать простого переименования атрибутов, которое запутывает точку)
CREATE ASSERTION <name for your constraint here>
CHECK NOT EXISTS (SELECT ANIMAL_TYPE, FOOD_TYPE
FROM ANIMALS NATURAL JOIN PREF_FOOD
WHERE (ANIMAL_TYPE, FOOD_TYPE) NOT IN
SELECT ANIMAL_TYPE, FOOD_TYPE FROM FOOD_TYPE);
Но ваш средний движок SQL не поддерживает утверждения. Поэтому вам нужно использовать ограничения CHECK. Например, для таблицы PREF_FOOD необходимое ограничение CHECK может выглядеть примерно так:
CHECK EXISTS (SELECT 1
FROM FOOD NATURAL JOIN ANIMAL
WHERE ANIMAL_TYPE = <animal type of inserted row> AND
FOOD_TYPE = <food type of inserted row>);
Теоретически этого должно быть достаточно для обеспечения соблюдения вашего ограничения, но опять же, ваш средний механизм SQL снова не будет поддерживать такого рода ограничение CHECK из-за ссылок на таблицы, отличные от той, для которой определено ограничение.
Таким образом, у вас есть варианты: прибегнуть к довольно сложным (*) настройкам, таким как catcall, или принудить ограничение с помощью триггеров (и вам придется написать довольно много из них (по крайней мере, три или шесть, не продумали это подробно), и ваш следующий лучший вариант - обеспечить это в коде приложения, и снова будет три или шесть (более или менее) отдельных мест, где необходимо реализовать одинаковое количество отдельных проверок.
Во всех этих трех сценариях желательно задокументировать существование ограничения и его суть в другом месте. Ни один из трех не сделает очевидным для стороннего лица, читающего этот дизайн, о чем, черт возьми, все это идет.
(*) «сложный» может быть не совсем правильным словом, но обратите внимание, что такие решения основаны на преднамеренной избыточности, поэтому намеренно ниже 3NF в дизайне. А это означает, что ваш дизайн подвержен аномалиям обновления, а это означает, что пользователю будет сложнее обновлять базу данных И поддерживать ее согласованность (именно из-за преднамеренного дублирования).
person
Erwin Smout
schedule
26.09.2012