Реляционные базы данных не созданы, чтобы справиться с этой ситуацией идеально. Вы должны решить, что является наиболее важным для вас, а затем сделать свой компромисс. У вас есть несколько целей:
- Поддерживать третью нормальную форму
- Поддерживать ссылочную целостность
- Поддерживайте ограничение на то, что каждая учетная запись принадлежит корпорации или физическому лицу.
- Сохранение возможности извлечения данных просто и напрямую
Проблема в том, что некоторые из этих целей конкурируют друг с другом.
Решение для подтипа
Вы можете выбрать решение для подтипа, в котором вы создаете супертип, в который входят как корпорации, так и отдельные лица. Этот супертип, вероятно, будет иметь составной ключ натурального ключа подтипа плюс атрибут разделения (например customer_type
). Это нормально в том, что касается нормализации, и позволяет вам обеспечивать ссылочную целостность, а также ограничение взаимной исключительности корпораций и отдельных лиц. Проблема в том, что это делает поиск данных более сложным, потому что вы всегда должны переходить в зависимости от того, customer_type
когда вы присоединяете учетную запись к владельцу учетной записи. Это, вероятно, означает использование UNION
и наличие большого количества повторяющихся SQL в вашем запросе.
Решение с
двумя внешними ключами Вы можете выбрать решение, в котором вы храните два внешних ключа в своей учетной записи: один для корпорации и один для человека. Это решение также позволяет поддерживать ссылочную целостность, нормализацию и взаимную исключительность. Он также имеет тот же недостаток поиска данных, что и решение для подтипа. На самом деле, это решение похоже на решение для подтипа, за исключением того, что вы попадаете на проблему ветвления логики объединения «раньше».
Тем не менее, многие разработчики моделей данных посчитали бы, что это решение уступает решению для подтипа из-за способа применения ограничения взаимной исключительности. В решении для подтипа вы используете ключи для обеспечения взаимной исключительности. В решении с двумя внешними ключами вы используете CHECK
ограничение. Я знаю некоторых людей, которые имеют необоснованное предубеждение против проверочных ограничений. Эти люди предпочли бы решение, которое сохраняет ограничения в ключах.
Решение «денормализованных» атрибутов разделения
Существует еще один вариант, когда вы сохраняете один столбец внешнего ключа в таблице контрольного счета и используете другой столбец, чтобы сообщить вам, как интерпретировать столбец внешнего ключа (RoKa'sOwnerTypeID
колонка). Это по существу исключает таблицу супертипа в решении подтипирования путем денормализации атрибута разделения на дочернюю таблицу. (Обратите внимание, что это не является строго «денормализацией» в соответствии с формальным определением, потому что атрибут разделения является частью первичного ключа.) Это решение кажется довольно простым, поскольку оно позволяет избежать использования дополнительной таблицы для более или менее одинакового действия, и сокращает количество столбцов внешнего ключа до одного. Проблема с этим решением состоит в том, что оно не избегает ветвления логики поиска и, более того, оно не позволяет поддерживать декларативную ссылочную целостность. Базы данных SQL не имеют возможности управлять одним столбцом внешнего ключа для одной из нескольких родительских таблиц.
Решение общего домена первичного ключа
Один из способов, с помощью которого люди иногда решают эту проблему, заключается в использовании одного пула идентификаторов, чтобы не было путаницы для любого данного идентификатора, независимо от того, принадлежит ли он к одному подтипу или другому. Это, вероятно, будет работать вполне естественно в банковском сценарии, поскольку вы не собираетесь выдавать один и тот же номер банковского счета как корпорации, так и физическому лицу. Это имеет то преимущество, что избегает необходимости в атрибуте разделения. Вы можете сделать это с таблицей супер-типа или без нее. Использование таблицы супертипа позволяет использовать декларативные ограничения для обеспечения уникальности. В противном случае это должно быть обеспечено в процедурном порядке. Это решение нормализовано, но оно не позволит вам поддерживать декларативную ссылочную целостность, если вы не сохраните таблицу супертипа. Это все еще не делает ничего, чтобы избежать сложной логики поиска.
Таким образом, вы можете видеть, что на самом деле невозможно иметь чистый дизайн, который бы соответствовал всем правилам, в то же время сохраняя простой поиск данных. Вы должны решить, где ваши компромиссы будут.
OwnerTypeID
вChecquingAccount
таблице, с1=Corporation
и2=NaturalPerson
? Таким образом, вам нужен только одинOwnerID
элемент вChecquingAccount
таблице, который вы можете индексировать вместе сOwnerTypeID
.