繁体   English   中英

跨多个表的SQL外键

[英]SQL Foreign Key across multiple tables

我正在建模检查。 检查表格是任意的,本质上是字段列表。

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,并为ToiletShowerFloor字段,我们将具有如下所示的值:

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)

这是一个FOREIGN KEY 我希望InspectionValues具有引用InspectionFormFieldsFOREIGN KEY 但它没有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跨多个跨越InspectionForms )。 一种简单有效的方法是确保在每次更新时此查询均不返回任何行:

SELECT InspectionId
FROM InspectionValues a
GROUP BY InspectionId
HAVING MIN(InspectionFormId) < MAX(InspectionFormId);

解决方案2: InspectionValues表存储对特定Inspection的引用,该引用又存储对特定InspectionForm的引用。 我可以简单地创建一个与InspectionValue Inspection组合的外键配对InspectionFormFields

如果这不可能,也许我可以在每次更新中以某种方式强制该查询不返回任何行:

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。 在这里做什么正确的事?

您应该将InspectionFormId保留在Inspections表中(而不是按照您的建议移动它)。 由于InspectionId是主键,因此每个Inspectionid不能只有一个InspectionFormID。

CREATE TABLE Inspections
(
InspectionId INT PRIMARY KEY,
InspectionFormId INT FOREIGN KEY REFERENCES InspectionForms,
);

然后将inspectionformid添加到inspectionvalues表中:

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的外键,但是您只需要一个多列,如上所示。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM