SQL Server中为表设置两个关联同表的外键报错如何解决?
错误成因
- SQL Server有内置的级联操作限制,禁止同一张表出现多个指向同一个源表的级联操作路径,避免级联执行时出现重复修改、死锁等不可预期的问题。
- 你当前的场景下,MESSAGE表的
WRITER、RECEIVER两个外键都指向USERINFO表的主键,且都设置了ON DELETE SET NULL的级联规则,当USERINFO表中的某条用户记录被删除时,会触发两条并行的级联置空路径,触发了SQL Server的校验限制,因此抛出错误。
解决方法
推荐使用「外键取消级联规则+触发器实现业务逻辑」的方案,既保留外键的数据一致性约束能力,也能实现删除用户后对应消息的发送/接收人字段置空的需求。
步骤1:修改建表语句
将两个外键的级联规则改为ON DELETE NO ACTION(默认不写就是该规则),先完成表结构创建:
CREATE TABLE USERINFO( USERID CHAR(20) NOT NULL, PW CHAR(20), POINT INT DEFAULT 5000, PRIMARY KEY(USERID) ); CREATE TABLE MESSAGE( NO INT NOT NULL IDENTITY(1,1), WRITER CHAR(20) DEFAULT NULL, RECEIVER CHAR(20) DEFAULT NULL, CONTENT CHAR(100), PRIMARY KEY(NO), FOREIGN KEY(WRITER) REFERENCES USERINFO(USERID) ON DELETE NO ACTION, FOREIGN KEY(RECEIVER) REFERENCES USERINFO(USERID) ON DELETE NO ACTION );
步骤2:创建触发器实现置空逻辑
创建INSTEAD OF DELETE触发器,在删除用户前先处理关联消息的字段置空,完全实现你原本需要的ON DELETE SET NULL效果:
CREATE TRIGGER TRG_USERINFO_DELETE ON USERINFO INSTEAD OF DELETE AS BEGIN -- 置空该用户发送的消息的发送人字段 UPDATE MESSAGE SET WRITER = NULL WHERE WRITER IN (SELECT USERID FROM DELETED); -- 置空该用户接收的消息的接收人字段 UPDATE MESSAGE SET RECEIVER = NULL WHERE RECEIVER IN (SELECT USERID FROM DELETED); -- 执行用户删除操作 DELETE FROM USERINFO WHERE USERID IN (SELECT USERID FROM DELETED); END
内容的提问来源于stack exchange,提问作者박상범
相关产品推荐
相关产品推荐

