¿Cómo modelo la relación de cero o uno a cero o uno en Sql Server de la manera más natural?
Hay una tabla de 'Peligro' que enumera los peligros en un sitio. Hay una tabla de "Tareas" para el trabajo que debe hacerse en un sitio. Algunas tareas son para solucionar un peligro, ninguna tarea puede hacer frente a múltiples peligros. Algunos peligros tienen la tarea de solucionarlos. Ningún peligro puede tener dos tareas asociadas con ellos.
Lo siguiente es lo mejor que se me ocurre:
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
¿Harías eso de manera diferente? La razón por la que no estoy contento con esta configuración es que debe existir una lógica de aplicación para asegurarse de que las tareas y los peligros se señalen entre sí y no a otras tareas y peligros, y que ninguna tarea / peligro señale al mismo peligro / tarea otra tarea / puntos de peligro a.
¿Hay una mejor manera?
fuente
null
.CREATE UNIQUE INDEX x ON dbo.Hazards(TaskID) WHERE TaskID IS NOT NULL;
Respuestas:
Puede seguir su propia idea de un esquema asimétrico eliminando una de las claves externas de la configuración actual o, para mantener las cosas simétricas, puede eliminar ambas claves externas e introducir una tabla de unión con una restricción única en cada referencia .
Entonces, sería así:
También puede declarar
(HazardId, TaskId)
que es la clave principal si necesita hacer referencia a estas combinaciones desde otra tabla. Sin embargo, con el fin de mantener los pares únicos, la clave primaria es innecesaria, es suficiente que cada ID sea única.fuente
(HazardId, TaskId)
tiene las tuplas(HazardId)
y(TaskId)
ambas identifican una fila de esta tabla de manera única. Uno de ellos debe seleccionarse como clave principal.Para resumir:
Si las tablas de tareas y riesgos se usan para otra cosa (es decir, las tareas y / o los riesgos tienen otros datos asociados, y el modelo que nos mostró está simplificado para mostrar solo los campos relevantes), diría que su solución es correcta.
De lo contrario, si las Tareas y los Peligros solo existen para combinarse entre sí, no necesita dos tablas; Puede crear una sola tabla para su relación, con los siguientes campos:
fuente
TaskID
yHazardID
? Podría tener 2 columnas BITIsTask
,IsHazard
y una restricción de que no ambas son falsas. Entonces laHazard
tabla es simplemente una vista:CRAETE VIEW Hazard SELECT HazardID = ID, HazardDetails, ... FROM ThisTable WHERE IsHazard = 1;
y Tarea respectivamente.Otro enfoque que parece no haber sido mencionado todavía es hacer que Hazards and Tasks use el mismo espacio de ID. Si un peligro tiene una tarea, tendrá la misma identificación. Si una tarea es para un peligro, tendrá la misma identificación.
Usaría una secuencia en lugar de columnas de identidad para completar estos ID.
Las consultas sobre este tipo de modelo de datos utilizarían combinaciones externas (completas) para recuperar sus resultados.
Este enfoque es muy similar a la respuesta de @ AndriyM, excepto que su respuesta permite que los ID sean diferentes y una tabla para almacenar esta relación.
No estoy seguro de que desee utilizar este enfoque para un escenario de dos tablas, pero funciona bien cuando aumenta el número de tablas involucradas.
fuente