问题描述
我有两张桌子,
CREATE TABLE ActivityCodes (
ActivityCodeID INT NOT NULL PRIMARY KEY,LocationID INT NOT NULL
);
和
CREATE TABLE LocationSettings (
LocationID INT NOT NULL PRIMARY KEY,DefaultFooActivityCodeID INT,FOREIGN KEY (DefaultFooActivityCodeID) REFERENCES ActivityCodes(ActivityCodeID)
);
与所示的外键关系。活动代码仅对给定的 LocationID
有效,DefaultFooActivityCodeID
表中的 LocationSettings
应为 ActivityCodeID
,其中 ActivityCodes.LocationID == LocationSettings.LocationID
。如何在 sql 中强制执行?可以用约束或外键来完成吗?有可能吗?
编辑:只是添加一些说明,这些表中的有效数据应该是这样的:
ActivityCodes
ActivityCodeID | 位置 ID |
---|---|
1 | 123 |
2 | 123 |
3 | 456 |
4 | 456 |
LocationSettings
位置 ID | DefaultFooActivityCodeID |
---|---|
123 | 1 |
456 | 4 |
一个地点可以有多个活动代码。位置的默认活动代码必须是该位置的活动代码。 @Charlieface 我尝试使用 answer you linked 中建议的复合外键,但是我收到一个错误,说 LocationID
上的 ActivityCodes
既不是唯一键也不是主键(我使用的是 MS sql Server ).
解决方法
您提供的 DDL 并不代表您所描述的内容。
DDL 描述了这一点:
ActivityCodes
独立于 LocationSettings
。
LocationSettings
而是依赖于 ActivityCodes
(一个 ActivityCodes 有多个 LocationSettings
)
外键的定义很好,比如 FOREIGN KEY (DefaultFooActivityCodeID) REFERENCES ActivityCodes(ActivityCodeID)
。如果您在没有先插入 ActivityCode 的情况下尝试插入 LocationSettings,则会因违反约束而失败。
外键引用不必是主键。这允许您对同一个表有两个外键引用,即使它们是多余的:
CREATE TABLE ActivityCodes (
ActivityCodeID INT NOT NULL PRIMARY KEY,LocationID INT NOT NULL,UNIQUE (LocationID,ActivityCodeID)
);
CREATE TABLE LocationSettings (
LocationID INT NOT NULL PRIMARY KEY,DefaultFooActivityCodeID INT,FOREIGN KEY (DefaultFooActivityCodeID) REFERENCES ActivityCodes(ActivityCodeID),FOREIGN KEY (LocationID,DefaultFooActivityCodeID) REFERENCES ActivityCodes(LocationID,ActivityCodeID)
);
虽然这表达了你想要的,但你会发现这在实践中维护起来有点棘手。设置默认值需要以下步骤:
- 插入具有
NULL
默认值的位置。 - 使用默认活动在
ActivityCodes
中插入一行。 - 更新
LocationSettings
中的默认值。