我一点也不喜欢“虚假”的数据。如果一个事件只涉及一个合同,或者没有合同,那么我会采取这样的方法:
CREATE TABLE dbo.Project
(
ProjectID INT IDENTITY,
Filler CHAR(1) NULL,
CONSTRAINT PK_Project__ProjectID PRIMARY KEY (ProjectID)
);
CREATE TABLE dbo.Contract
(
ContractID INT IDENTITY,
ProjectID INT NOT NULL,
Filler CHAR(1) NULL,
CONSTRAINT PK_Contract__ContractID PRIMARY KEY (ContractID),
CONSTRAINT FK_Contract__ProjectID FOREIGN KEY (ProjectID) REFERENCES dbo.Project (ProjectID),
CONSTRAINT UQ_Contract__ContractID_ProjectID UNIQUE (ContractID, ProjectID)
);
CREATE TABLE dbo.Incident
(
IncidentID INT IDENTITY,
ProjectID INT NOT NULL,
ContractID INT NULL,
Filler CHAR(1) NULL,
CONSTRAINT PK_Incident__IncidentID PRIMARY KEY (IncidentID),
CONSTRAINT FK_Incident__ProjectID FOREIGN KEY (ProjectID) REFERENCES dbo.Project (ProjectID),
CONSTRAINT FK_Incident__ContractID FOREIGN KEY (ContractID, ProjectID) REFERENCES dbo.Contract (ContractID, ProjectID)
);
INSERT dbo.Project DEFAULT VALUES;
INSERT dbo.Project DEFAULT VALUES;
INSERT dbo.Contract (ProjectID)
SELECT ProjectID
FROM Project;
INSERT dbo.Incident (ProjectID)
SELECT ProjectID
FROM Project;
INSERT dbo.Incident (ContractID, ProjectID)
SELECT ContractID, ProjectID
FROM dbo.Contract;
INSERT dbo.Incident (ContractID, ProjectID)
SELECT c.ContractID, p.ProjectID
FROM dbo.Project AS p
CROSS JOIN dbo.Contract AS c
WHERE c.ProjectID != p.ProjectID;
这将会以错误的方式失败:
>The INSERT statement conflicted with the FOREIGN KEY constraint "FK_Incident__ContractID". The conflict occurred in database "TestDB", table "dbo.Contract".
外键可以引用对Contract
的唯一约束,这使您能够在dbo.Incident
中强制执行完整性,即您不能输入不正确映射到正在输入的合同的项目。场景的唯一真正缺点是当填充ContractID
时,您会复制ProjectID
,但我认为这不是一个重大问题。肯定(在我看来)比虚拟数据少得多。
然后很容易识别虚拟合同:
SELECT *
FROM dbo.Incident
WHERE ContractID IS NULL;