我正在模拟检查。检查表格是任意的,基本上是一个字段列表。
CREATE TABLE InspectionForms
(
InspectionFormId INT PRIMARY KEY,
InspectionFormName NVARCHAR(64),
... (CreatorId, TimeCreated, etc.)
);
CREATE TABLE InspectionFormFields
(
InspectionFormId INT FOREIGN KEY REFERENCES InspectionForms,
InspectionFormFieldId INT,
FieldName NVARCHAR(64),
PRIMARY KEY(InspectionFormId, InspectionFormFieldId)
);
因此,使用名为Bathroom
的InspectionForm,包含Toilet
,Shower
和Floor
的字段,我们的值将如下所示:
InspectionForms
---------------
0 Bathroom
InspectionFormFields
--------------------
0 0 Toilet
0 1 Shower
0 2 Floor
然后有实际完成的检查:
CREATE TABLE Inspections
(
InspectionId INT PRIMARY KEY,
InspectionFormId INT FOREIGN KEY REFERENCES InspectionForms,
... (InspectorId, TimeOfInspection, etc.)
);
CREATE TABLE InspectionValues
(
InspectionId INT FOREIGN KEY REFERENCES Inspections,
InspectionFormFieldId INT,
Rating TINYINT NOT NULL,
PRIMARY KEY(InspectionId, InspectionFormFieldId)
);
以下是一些示例值:
Inspections
-----------
0 0 ...
InspectionValues
----------------
0 0 5 (Inspection 0 scored a 5 in the Toilet)
0 1 3 (Inspection 0 scored a 3 in the Shower)
0 2 4 (Inspection 0 scored a 4 in the Floor)
以下是踢球者:我希望InspectionValues
引用FOREIGN KEY
引用InspectionFormFields
。但它没有InspectionFormId
列。我可以想到两个理论解决方案,但我不知道如何实现其中任何一个。
解决方案1:我只需将InspectionFormId
列从Inspections
移至InspectionValues
,然后添加我的外键即可。这会使我们的表看起来像这样:
CREATE TABLE InspectionValues
(
InspectionId INT FOREIGN KEY REFERENCES Inspections,
InspectionFormId INT FOREIGN KEY REFERENCES InspectionForms,
InspectionFormFieldId INT,
Rating TINYINT NOT NULL,
PRIMARY KEY(InspectionId, InspectionFormId, InspectionFormFieldId),
FOREIGN KEY(InspectionFormId, InspectionFormFieldId) REFERENCES InspectionFormFields
);
如果我这样做,我想以某种方式强制执行所有InspectionValues
与给定InspectionId
共享InspectionFormId
的共同值(即我不想要Inspection
1}}跨越多个InspectionForms
)。一种简单有效的方法是确保在每次更新时,此查询都不会返回任何行:
SELECT InspectionId
FROM InspectionValues a
GROUP BY InspectionId
HAVING MIN(InspectionFormId) < MAX(InspectionFormId);
解决方案2 InspectionValues
表存储对特定Inspection
的引用,该引用又存储对特定InspectionForm
的引用。我可以简单地创建一个外键配对InspectionFormFields
与InspectionValue
- Inspection
组合
如果那是不可能的,也许我可以在每次更新时以某种方式强制执行此查询不返回任何行:
SELECT *
FROM InspectionValues a
JOIN Inspections b ON a.InspectionId = b.InspectionId
JOIN InspectionForms c ON b.InspectionFormId = c.InspectionFormId
WHERE NOT EXISTS (
SELECT *
FROM InspectionFormFields d
WHERE a.InspectionFormFieldId = d.InspectionFormFieldId AND b.InspectionFormId = d.InspectionFormId
);
我使用的是SQL Server 2014,并且不需要支持任何其他版本的SQL。在这里做什么是正确的?
答案 0 :(得分:2)
您应该将CheckFormId保留在Inspections表中(而不是按照您的建议移动它)。由于InspectionId是主键,因此每个inspectid不能只有一个inspectionformid。
CREATE TABLE Inspections
(
InspectionId INT PRIMARY KEY,
InspectionFormId INT FOREIGN KEY REFERENCES InspectionForms,
);
然后将inspectionformid添加到检查值表:
CREATE TABLE InspectionValues
(
InspectionId INT FOREIGN KEY REFERENCES Inspections,
InspectionFormId INT,
InspectionFormFieldId INT,
Rating TINYINT NOT NULL,
PRIMARY KEY(InspectionId, InspectionFormId, InspectionFormFieldId),
FOREIGN KEY(InspectionFormId, InspectionFormFieldId)
REFERENCES InspectionFormFields(InspectionFormId, InspectionFormFieldId)
);
在上面的解决方案1中,InspectionValues有两个包含InspectionFormId的外键,但您只需要如上所示的多列外键。