Как мне естественным образом смоделировать отношение «ноль или один к нулю или один» в Sql Server?
Существует таблица «Опасность», в которой перечислены опасности на сайте. Существует таблица «Задачи» для работы, которую необходимо выполнить на сайте. Некоторые задачи заключаются в устранении опасности, ни одна задача не может справиться с несколькими опасностями. У некоторых опасностей есть задача их исправить. Никакая опасность не может иметь две задачи, связанные с ними.
Ниже это лучшее, что я мог придумать:
CREATE TABLE [dbo].[Hazard](
[HazardId] [int] IDENTITY(1,1) NOT NULL,
[TaskId] [int] NULL,
[Details] [varchar](max) NULL,
CONSTRAINT [PK_Hazard] PRIMARY KEY CLUSTERED
(
[HazardId] ASC
))
GO
ALTER TABLE [dbo].[Hazard] WITH CHECK ADD CONSTRAINT [FK_Hazard_Task] FOREIGN KEY([TaskId])
REFERENCES [dbo].[Task] ([TaskId])
GO
CREATE TABLE [dbo].[Task](
[TaskId] [int] IDENTITY(1,1) NOT NULL,
[HazardId] [int] NULL,
[Details] [varchar](max) NULL,
CONSTRAINT [PK_Task] PRIMARY KEY CLUSTERED
(
[TaskId] ASC
))
GO
ALTER TABLE [dbo].[Task] WITH CHECK ADD CONSTRAINT [FK_Task_Hazard] FOREIGN KEY([HazardId])
REFERENCES [dbo].[Hazard] ([HazardId])
GO
Вы бы сделали это по-другому? Причина, по которой я не доволен этой настройкой, заключается в том, что должна существовать логика приложения, чтобы убедиться, что задачи и опасности указывают друг на друга, а не на другие задачи и опасности, и что ни одна задача / опасность не указывает на одну и ту же опасность / задачу другая задача / опасность указывает на.
Есть ли способ лучше?
источник
null
.CREATE UNIQUE INDEX x ON dbo.Hazards(TaskID) WHERE TaskID IS NOT NULL;
Ответы:
Вы можете пойти с вашей собственной идеей асимметричной схемы, удалив один из внешних ключей из текущей установки, или, чтобы сохранить симметрию, вы можете удалить оба внешних ключа и ввести таблицу соединений с уникальным ограничением для каждой ссылки. ,
Итак, это было бы так:
Вы могли бы дополнительно объявить
(HazardId, TaskId)
первичный ключ, если вам нужно сослаться на эти комбинации из другой таблицы. Однако для сохранения уникальности пар первичный ключ не нужен, достаточно, чтобы каждый идентификатор был уникальным.источник
(HazardId, TaskId)
имеет кортежи,(HazardId)
и(TaskId)
оба идентифицируют строку этой таблицы однозначно. Один из них должен быть выбран в качестве первичного ключа.Подводить итоги:
Если таблицы «Задача» и «Опасность» используются для чего-то другого (например, задачи и / или опасности связаны с другими данными, а модель, которую вы нам показали, упрощена и отображает только соответствующие поля), я бы сказал, что ваше решение верное.
В противном случае, если задачи и опасности существуют только для связи друг с другом, вам не нужны две таблицы; Вы можете создать одну таблицу для их отношений со следующими полями:
источник
TaskID
иHazardID
? Вы можете иметь 2 BIT колонки,IsTask
,IsHazard
и ограничение, но не оба из них являются ложными. ТогдаHazard
таблица - это просто представление:CRAETE VIEW Hazard SELECT HazardID = ID, HazardDetails, ... FROM ThisTable WHERE IsHazard = 1;
и Задача соответственно.Другой подход, который, кажется, еще не был упомянут, состоит в том, чтобы Опасности и Задачи использовали одно и то же пространство идентификаторов. Если у Опасности есть Задача, у нее будет тот же идентификатор. Если Задача предназначена для Опасности, она будет иметь такой же идентификатор.
Для заполнения этих идентификаторов вы должны использовать последовательность, а не столбцы идентификаторов.
Запросы к этому типу модели данных будут использовать (полные) внешние объединения для получения своих результатов.
Этот подход очень похож на ответ @ AndriyM, за исключением того, что его ответ позволяет идентифицировать идентификаторы и таблицу для хранения этих отношений.
Я не уверен, что вы хотите использовать этот подход для сценария с двумя столами, но он хорошо работает, когда количество задействованных таблиц увеличивается.
источник