제로 또는 제로 또는 제로 또는 제로


9

가장 자연스러운 방법으로 Sql Server에서 0 대 1 대 0 또는 1 관계를 어떻게 모델링합니까?

사이트의 위험을 나열하는 '위험'테이블이 있습니다. 사이트에서 수행해야하는 작업에 대한 '작업'테이블이 있습니다. 일부 작업은 위험을 해결하기위한 것이며 여러 작업을 처리 할 수있는 작업은 없습니다. 일부 위험 요소에는 해결해야 할 작업이 있습니다. 어떤 위험도 그들과 관련된 두 가지 작업을 가질 수 없습니다.

아래는 내가 생각할 수있는 최선입니다.

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

다르게 하시겠습니까? 이 설정에 만족하지 않는 이유는 작업과 위험이 서로를 가리키고 다른 작업과 위험을 가리 키지 않도록하는 작업과 위험이 동일한 위험 / 작업을 가리 키지 않도록하는 응용 프로그램 논리가 필요하기 때문입니다 다른 작업 / 위험이 지적합니다.

더 좋은 방법이 있습니까?

여기에 이미지 설명을 입력하십시오


위험 테이블에서 TaskID에 고유 인덱스를 생성 할 수없고 작업 테이블에 고유 HazardID 인덱스를 작성할 수없는 이유가 있습니까? 그것은 당신이 테이블에 그들 중 하나만 가질 수 있도록 만들 것입니다.
mskinner

@mskinner지만 고유하지는 않지만 많은 사람들이 할 수 있습니다 null.
앤드류 Savinykh

아. 이 경우 Ben-Gan은 sqlmag.com/sql-server-2008/unique-constraint-multiple-nulls에서 여러 개의 null을 허용하는 제약 조건을 만드는 방법에 대해 글을 올렸습니다 . 나는 그것이 당신을 위해 일할 것이라고 생각합니다. 그렇지 않다면 알려주십시오.
mskinner

참고로 필터링 된 인덱스를 사용하는 데는 여러 가지 문제가 있으므로 익숙하지 않은 경우 읽을 수 있습니다. 여기에 좋은 블로그가 있습니다. blogs.msdn.com/b/sqlprogrammability/archive/2009/06/29/… 그러나이 특정 시나리오의 경우 다른 문제로 인해 슬픔을 유발하지 않는다고 가정하면 잘 작동 할 수 있습니다.
mskinner

FWIW 고유 필터링 된 인덱스는 null이 아닌 행에만 고유성을 적용 할 수 있습니다.CREATE UNIQUE INDEX x ON dbo.Hazards(TaskID) WHERE TaskID IS NOT NULL;
Aaron Bertrand

답변:


9

당신은 함께 갈 수있는 자신 만의 생각이 현재의 셋업에서 외래 키 중 하나를 제거하여 비대칭 스키마의, 또는, 대칭 물건을 유지하기 위해, 당신은 모두 외래 키를 제거하고 소개 할 수 접합 테이블을 각 기준에 대한 고유 제약 조건 .

따라서 다음과 같습니다.

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가 고유하면 충분합니다.


1
+1 나는 이것이 그러한 관계를 구현하는 가장 자연스러운 방법이라고 생각합니다. 하지만 최소한의 경우에만 데는 보통 하나는 튜플 차 같은 튜플을 선택 (HazardId, TaskId)튜플을 보유 (HazardId)하고 (TaskId)모두 고유이 테이블의 행을 식별하는 것이다. 그중 하나가 기본 키로 선택되어야합니다.
miracle173

2

요약하면 :

  • 위험은 하나 또는 제로 작업이 있습니다
  • 작업에는 하나 또는 제로 위험이 있습니다

작업 및 위험 테이블이 다른 용도로 사용되는 경우 (예 : 작업 및 / 또는 위험에 다른 데이터가 연결되어 있고 관련 필드 만 표시하기 위해 Google에 표시 한 모델이 단순화 된 경우) 솔루션이 올바른 것입니다.

그렇지 않으면 작업과 위험 요소 만 서로 연결되어있는 경우 두 개의 테이블이 필요하지 않습니다. 다음 필드를 사용하여 관계에 대한 단일 테이블을 작성할 수 있습니다.

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

1
필자는 각 경우에 필터링 된 색인이어야한다는 것을 분명히했습니다. (문제에 대한 설명에서 추측 할 수는 있지만 완전히 명확하게 보이지는 않습니다). 불필요하다고 생각하거나 다른 방식으로 아이디어를 전달하려는 경우 자유롭게 편집하십시오.
Andriy M

나는이 아이디어에 여전히 만족하지 못한다고 말해야한다. 문제는 TaskID 및 HazardID를 수동으로 생성해야한다는 것입니다. 이것이 2012 년이라면 시퀀스를 사용할 수는 있지만 나에게는 옳지 않은 것처럼 보입니다. 작업과 위험이라는 두 가지 요소가 완전히 다른 엔티티이기 때문에 단일 테이블에 저장한다는 아이디어와 조정하기가 어렵습니다.
Andriy M

이 디자인을 선택하면 왜 TaskIDand 가 필요 HazardID합니까? 당신은 2 비트 열을 가질 수있다 IsTask, IsHazard하지 둘 다 거짓 제약 조건을. 그런 다음 Hazard테이블은 단순히보기 CRAETE VIEW Hazard SELECT HazardID = ID, HazardDetails, ... FROM ThisTable WHERE IsHazard = 1;와 작업입니다.
ypercubeᵀᴹ

@ypercube 테이블에 형태가없는 것을 저장 한 다음 이진 필드를 사용하여 작업인지 위험인지를 알 수 있습니다. 못생긴 데이터베이스 모델링입니다.
dr_

@AndriyM 나는 이해하며, 대부분의 경우 같은 테이블에 두 종류의 다른 엔티티를 저장해서는 안된다는 데 동의 합니다. 그러나주의 사항을 읽으십시오 : 작업과 위험이 일대일 관계에 있고 이것에만 존재 하는 경우 단일 테이블을 사용하는 것이 허용됩니다.
dr_

1

아직 언급되지 않은 또 다른 접근법은 위험 요소와 작업이 동일한 ID 공간을 사용하도록하는 것입니다. 위험에 작업이있는 경우 동일한 ID를 갖습니다. 작업이 위험 대상인 경우 동일한 ID를 갖습니다.

ID 열 대신 시퀀스를 사용하여 이러한 ID를 채 웁니다.

이 유형의 데이터 모델에 대한 쿼리는 (전체) 외부 조인을 사용하여 결과를 검색합니다.

이 접근법은 @AndriyM의 답변과 매우 유사합니다. 그의 답변은 ID가 다르고이 관계를 저장하는 테이블을 허용합니다.

2 테이블 시나리오에이 방법을 사용하고 싶지는 않지만 관련된 테이블 수가 증가하면 잘 작동합니다.


기여해 주셔서 감사합니다. 나는 그 접근 방식도 고려했습니다. 시퀀스는 sql2008에서 구현하기가 어려우며 기꺼이 참을 수없는 것보다 더 많은 문제가 있기 때문에 결국 반대했습니다.
앤드류 Savinykh
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.