如何仅引用dbo.Events表的ImportId列?外键约束报错解决
首先咱们得搞清楚报错的核心原因:SQL Server要求外键引用的列,必须是被引用表的主键,或者是带有唯一约束/唯一索引的列(可以是单列,也可以是组合列)。
看你给出的dbo.Events表结构,里面的唯一约束UQ_Events是(ImportId, ImportTypeId)的组合唯一——也就是说,只有当这两个值组合起来才是唯一的,单独的ImportId并不是全局唯一的(同一个ImportId可能对应不同的ImportTypeId)。这就是直接引用ImportId作为外键会报错的原因,它不符合外键的引用规则。
接下来逐一回答你的问题:
1. 如何仅引用ImportId列?
如果你的业务逻辑允许ImportId在dbo.Events中全局唯一(也就是同一个ImportId不能对应不同的ImportTypeId),那可以给dbo.Events的ImportId单独添加一个唯一约束,让它满足外键引用的条件。
执行以下修改脚本:
-- 给dbo.Events的ImportId添加单列唯一约束 ALTER TABLE [dbo].[Events] ADD CONSTRAINT UQ_Events_ImportId UNIQUE (ImportId); GO
添加完成后,你原来的eventful.Events表创建脚本就能正常执行了,因为ImportId现在是唯一列,符合外键引用要求。
2. 是否必须在eventful.[Events]表中添加ImportTypeId字段?
如果你的业务逻辑需要保留原规则——也就是同一个ImportId可以对应不同的ImportTypeId(这也是当初设置组合唯一约束的初衷),那必须添加ImportTypeId字段到eventful.[Events]表中,然后用(ImportId, ImportTypeId)的组合列作为外键,引用dbo.Events中对应的组合唯一约束列。
修改后的eventful.[Events]表创建脚本示例:
DROP TABLE IF EXISTS [eventful].[Events] GO CREATE TABLE [eventful].[Events] ( [EventfulId] NVARCHAR(50) NOT NULL, [ImportTypeId] INT NOT NULL, -- 添加该字段 [ImportDate] DATETIME NOT NULL DEFAULT(GETUTCDATE()), [LastImportDate] DATETIME NULL, [Url] NVARCHAR(2048) NULL, CONSTRAINT PK_EventfulEvents PRIMARY KEY CLUSTERED (EventfulId), -- 组合外键匹配dbo.Events的唯一约束列 CONSTRAINT FK_EventfulEvents_Events FOREIGN KEY (EventfulId, ImportTypeId) REFERENCES [dbo].[Events](ImportId, ImportTypeId) ); GO
这样修改后,外键就对应了dbo.Events中的组合唯一约束,符合SQL Server的外键规则,脚本就能正常执行了。
总结一下:选哪种方案完全取决于你的业务需求——如果ImportId可以全局唯一,就加单列唯一约束;如果需要保留组合唯一的逻辑,就给eventful.[Events]加ImportTypeId并使用组合外键。
内容的提问来源于stack exchange,提问作者Mike Perrenoud

