Como modelar o relacionamento zero ou um para zero ou um no Sql Server da maneira mais natural?
Existe uma tabela 'Perigos' que lista os perigos em um site. Há uma tabela 'Tarefa' para o trabalho que precisa ser realizado em um site. Algumas tarefas são para corrigir um risco, nenhuma tarefa pode lidar com vários riscos. Alguns perigos têm uma tarefa para corrigi-los. Nenhum risco pode ter duas tarefas associadas a eles.
O abaixo é o melhor que eu poderia pensar:
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
Você faria isso de maneira diferente? O motivo pelo qual não estou satisfeito com essa configuração é que é preciso haver uma lógica de aplicativo para garantir que as tarefas e os perigos apontem um para o outro e não para outras tarefas e perigos e que nenhuma tarefa / perigo aponte para o mesmo perigo / tarefa outra tarefa / perigo aponta para.
Existe uma maneira melhor?
fonte
null
.CREATE UNIQUE INDEX x ON dbo.Hazards(TaskID) WHERE TaskID IS NOT NULL;
Respostas:
Você pode seguir sua própria idéia de um esquema assimétrico removendo uma das chaves estrangeiras da configuração atual ou, para manter as coisas simétricas, você pode remover as duas chaves estrangeiras e introduzir uma tabela de junção com uma restrição exclusiva em cada referência. .
Então, seria assim:
Além disso, você pode declarar
(HazardId, TaskId)
ser a chave primária se precisar fazer referência a essas combinações de outra tabela. Para manter os pares exclusivos, no entanto, a chave primária é desnecessária, basta que cada ID seja único.fonte
(HazardId, TaskId)
possui as tuplas(HazardId)
e(TaskId)
ambas identificam uma linha desta tabela exclusivamente. Um deles deve ser selecionado como chave primária.Resumindo:
Se as tabelas Tarefa e Perigo forem usadas para outra coisa (por exemplo, tarefas e / ou perigos têm outros dados associados, e o modelo que você nos mostrou é simplificado para mostrar apenas os campos relevantes), eu diria que sua solução está correta.
Caso contrário, se existir apenas tarefas e riscos para serem acoplados, você não precisará de duas tabelas; você pode criar uma única tabela para o relacionamento deles, com os seguintes campos:
fonte
TaskID
eHazardID
? Você pode ter 2 colunas BITIsTask
,IsHazard
e uma restrição de que ambas não sejam falsas. Então aHazard
tabela é simplesmente uma visualização:CRAETE VIEW Hazard SELECT HazardID = ID, HazardDetails, ... FROM ThisTable WHERE IsHazard = 1;
e Tarefa, respectivamente.Outra abordagem que parece não ter sido mencionada ainda é fazer com que Riscos e tarefas usem o mesmo espaço de identificação. Se um perigo tiver uma tarefa, ele terá o mesmo ID. Se uma tarefa é para um perigo, ela terá o mesmo ID.
Você usaria uma sequência em vez de colunas de identidade para preencher esses IDs.
As consultas nesse tipo de modelo de dados usariam junções externas (completas) para recuperar seus resultados.
Essa abordagem é muito semelhante à resposta de @ AndriyM, exceto que sua resposta permite que os IDs sejam diferentes e uma tabela para armazenar esse relacionamento.
Não tenho certeza se você deseja usar essa abordagem para um cenário de duas tabelas, mas funciona bem quando o número de tabelas envolvidas aumenta.
fonte