Разработка базы данных супертип-подтипов

У меня есть вопрос о дизайне супертип-подтипов в реляционной базе данных. Если бы у меня был супертип с двумя таблицами подтипов, у меня был бы PK супертипа, связанный с PK двух таблиц подтипов, как FK. Допустим, у меня была такая вещь:

Тип

TypeID PK

Supertype

ID ПК TypeID FK

SubtypeA

ИД ПК, ФК

SubtypeB

ИД ПК, ФК

Что касается базы данных, как я могу обеспечить, чтобы идентификаторы Supertype данного типа были помещены только в соответствующую таблицу подтипов? Например, я бы не хотел, чтобы идентификатор Supertype ID с типом A помещался в таблицу SubtypeB. Есть ли способ легко предотвратить это на стороне базы данных? Я знаю, что это может быть обработано в коде, но что, если код содержит ошибки? Или что, если кто-то вручную введет неправильный идентификатор в одну из таблиц подтипа? Я думаю, я ищу способ сделать это невозможным на стороне базы данных.

Есть идеи? Может быть, PK в таблице Supertype должен быть комбинацией ID и TypeID с уникальным ограничением на столбце ID, чтобы предотвратить попадание записи с обоими типами в таблицу SuperType... и тогда таблицы Subtype будут иметь комбинированный идентификатор и TypeID PK с ограничением на TypeID только того типа, который должен быть для соответствующей таблицы подтипов??

2 ответа

Что касается базы данных, как я могу обеспечить, чтобы идентификаторы Supertype данного типа были помещены только в соответствующую таблицу подтипов?

На СУБД, которая поддерживает отложенные ограничения, вы можете сделать что-то вроде этого:

Со следующим ограничением на SuperType:

CHECK (
    (
        (SubtypeAId IS NOT NULL AND SubtypeAId = SuperTypeId)
        AND SubtypeBId IS NULL
    )
    OR
    (
        SubtypeAId IS NULL
        AND (SubtypeBId IS NOT NULL AND SubtypeBId = SuperTypeId)
    )
)

Эти своеобразные круглые FKs 1 в сочетании с CHECK гарантируют как исключительность, так и присутствие ребенка (CHECK обеспечивает ровно одно из: SuprerType.SubtypeAId, SuprerType.SubtypeBId не равен NULL и соответствует SuperTypeId). Отложите дочерние FK (или ПРОВЕРЬТЕ, если ваша СУБД поддерживает это), чтобы устранить проблему "курица и яйцо" при вставке новых данных.

1 SubtypeA.SubtypeAId Рекомендации SuperType.SuperTypeId а также SuperType.SubtypeAId Рекомендации SubtypeA.SubtypeAId То же самое для другого подтипа.

Если ваша СУБД не поддерживает отложенные ограничения, вы можете разрешить (в ПРОВЕРКЕ), чтобы оба поля были ПУСТО (NULL), и отказаться от принудительного присутствия ребенка (вы по-прежнему сохраняете исключительность).


Альтернативно, только исключительность (но не присутствие) также может быть применена следующим образом:

ПРИМЕЧАНИЕ: вам может понадобиться добавить избыточный уникальный на SuperType {SuperTypeId, TypeId} если СУБД не поддерживает FK "вне ключа".

Со следующим ограничением на SubtypeA:

CHECK(TypeId = 1)

И следующее ограничение на SubtypeB:

CHECK(TypeId = 2)

Я использовал 1 и 2 для обозначения конкретных подтипов - вы можете использовать все, что вам нравится, если вы последовательны.

Кроме того, вы можете сэкономить место на диске, используя рассчитанный столбец для подтипа TypeId (например, виртуальные колонки Oracle 11).


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


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

Взгляните на этот пост для получения дополнительной информации.

Используйте триггер для распространения новой записи в таблице супертипов в соответствующую таблицу подтипов.

Другие вопросы по тегам