web-dev-qa-db-ja.com

0または1から0または1

SQL Serverでゼロまたは1対0または1の関係を最も自然な方法でモデル化するにはどうすればよいですか?

サイトの危険をリストした「ハザード」テーブルがあります。サイトで実行する必要がある作業用の「タスク」テーブルがあります。一部のタスクはハザードを修正することであり、タスクは複数のハザードを処理することはできません。一部のハザードにはそれらを修正するタスクがあります。ハザードには2つのタスクを関連付けることができません。

以下は私が考えることができる最高のものです:

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

違う方法でやってみませんか?この設定に不満なのは、タスクとハザードが他のタスクとハザードではなく、お互いを指すようにし、同じハザード/タスクを指すタスク/ハザードがないことを確認するためのアプリケーションロジックが必要なためです。別のタスク/ハザードが指します。

もっと良い方法はありますか?

enter image description here

9
Andrew Savinykh

現在の設定から外部キーの1つを削除することにより、非対称スキーマの 独自のアイデア を使用するか、または対称性を維持するために、両方の外部キーを削除して-を導入することができます。 junction table 各参照に一意の制約があります。

したがって、次のようになります。

CREATE TABLE dbo.Hazard
(
  HazardId int IDENTITY(1,1) NOT NULL CONSTRAINT PK_Hazard PRIMARY KEY CLUSTERED,
  Details varchar(max) NULL
);

CREATE TABLE dbo.Task
(
  TaskId int IDENTITY(1,1) NOT NULL CONSTRAINT PK_Task PRIMARY KEY CLUSTERED,
  Details varchar(max) NULL,
);

CREATE TABLE dbo.HazardTask
(
  HazardId int NOT NULL
    CONSTRAINT FK_HazardTask_Hazard FOREIGN KEY REFERENCES dbo.Hazard (HazardId)
    CONSTRAINT UQ_HazardTask_Hazard UNIQUE,
  TaskId int NOT NULL
    CONSTRAINT FK_HazardTask_Task FOREIGN KEY REFERENCES dbo.Task (TaskId)
    CONSTRAINT UQ_HazardTask_Task UNIQUE
);

別のテーブルからこれらの組み合わせを参照する必要がある場合は、(HazardId, TaskId)を主キーとしてさらに宣言できます。ただし、ペアを一意に保つために、主キーは不要です。各IDが一意であれば十分です。

9
Andriy M

総括する:

  • ハザードのタスクは1つまたはゼロ
  • タスクには1つまたはゼロのハザードがあります

タスクテーブルとハザードテーブルが別の目的で使用されている場合(つまり、タスクやハザードに他のデータが関連付けられており、表示されたモデルが単純化されて関連フィールドのみが表示されている場合)ソリューションは正しいと思います。

それ以外の場合、タスクとハザードが互いに結合するためだけに存在する場合、2つのテーブルは必要ありません。次のフィールドを使用して、リレーションシップの単一のテーブルを作成できます。

ID            int, PK
TaskID        int, (filtered) unique index  
TaskDetails   varchar
HazardID      int, (filtered) unique index
HazardDetails varchar
2
dr_

まだ言及されていないように思われる別のアプローチは、ハザードとタスクに同じIDスペースを使用させることです。ハザードにタスクがある場合、そのIDは同じになります。タスクがハザード用である場合、同じIDが割り当てられます。

これらのIDを設定するには、ID列ではなくシーケンスを使用します。

このタイプのデータモデルのクエリは、(完全)外部結合を使用して結果を取得します。

このアプローチは、@ AndriyMの回答と非常に似ていますが、彼の回答ではIDが異なることと、この関係を格納するテーブルが許可されています。

このアプローチを2つのテーブルのシナリオに使用するかどうかはわかりませんが、関係するテーブルの数が増えるとうまくいきます。

1
Colin 't Hart