Comment modéliser la relation zéro ou un à zéro ou un dans Sql Server de la manière la plus naturelle?
Il existe un tableau des «dangers» qui répertorie les dangers sur un site. Il existe une table «Tâche» pour le travail qui doit être effectué sur un site. Certaines tâches consistent à corriger un danger, aucune tâche ne peut faire face à plusieurs dangers. Certains dangers ont pour tâche de les résoudre. Aucun danger ne peut être associé à deux tâches.
Ce qui suit est le meilleur auquel j'ai pu penser:
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
Le feriez-vous différemment? La raison pour laquelle je ne suis pas satisfait de cette configuration est qu'il doit y avoir une logique d'application pour s'assurer que les tâches et les dangers pointent les uns vers les autres et non vers d'autres tâches et dangers et qu'aucune tâche / danger ne pointe vers le même danger / tâche. une autre tâche / un danger indique.
Y a-t-il une meilleure façon?
la source
null
.CREATE UNIQUE INDEX x ON dbo.Hazards(TaskID) WHERE TaskID IS NOT NULL;
Réponses:
Vous pouvez utiliser votre propre idée d'un schéma asymétrique en supprimant l'une des clés étrangères de la configuration actuelle, ou, pour garder la symétrie, vous pouvez supprimer les deux clés étrangères et introduire une table de jonction avec une contrainte unique sur chaque référence. .
Donc, ce serait comme ça:
Vous pouvez également déclarer
(HazardId, TaskId)
être la clé primaire si vous devez référencer ces combinaisons à partir d'une autre table. Dans le but de garder les paires uniques, cependant, la clé primaire n'est pas nécessaire, il suffit que chaque ID soit unique.la source
(HazardId, TaskId)
a les tuples(HazardId)
et(TaskId)
que les deux identifient une ligne de ce tableau de façon unique. L'un d'eux doit être sélectionné comme clé primaire.Pour résumer:
Si les tableaux des tâches et des dangers sont utilisés pour autre chose (c'est-à-dire que les tâches et / ou les dangers ont d'autres données associées et que le modèle que vous nous avez montré est simplifié pour ne montrer que les champs pertinents), je dirais que votre solution est correcte.
Sinon, si les tâches et les dangers n'existent que pour être couplés les uns aux autres, vous n'avez pas besoin de deux tables; vous pouvez créer une seule table pour leur relation, avec les champs suivants:
la source
TaskID
etHazardID
? Vous pouvez avoir 2 colonnes BITIsTask
,IsHazard
et une contrainte selon laquelle les deux ne sont pas fausses. LeHazard
tableau est alors simplement une vue:CRAETE VIEW Hazard SELECT HazardID = ID, HazardDetails, ... FROM ThisTable WHERE IsHazard = 1;
et Task respectivement.Une autre approche qui ne semble pas encore être mentionnée consiste à faire en sorte que les dangers et les tâches utilisent le même espace d'identification. Si un danger a une tâche, il aura le même ID. Si une tâche concerne un danger, elle aura le même ID.
Vous utiliseriez une séquence plutôt que des colonnes d'identité pour remplir ces ID.
Les requêtes sur ce type de modèle de données utiliseraient des jointures externes (complètes) pour récupérer leurs résultats.
Cette approche est très similaire à la réponse de @ AndriyM, sauf que sa réponse permet que les ID soient différents et une table pour stocker cette relation.
Je ne suis pas sûr que vous souhaitiez utiliser cette approche pour un scénario à deux tables, mais cela fonctionne bien lorsque le nombre de tables impliquées augmente.
la source