我在MS visual studio项目的基于服务的数据库(Microsoft SQL)中创建了下表:
CREATE TABLE [dbo].[users] (
[phone_number] VARCHAR (50) NOT NULL,
[name] VARCHAR (50) NOT NULL,
[picture] VARCHAR (50) NOT NULL,
[password] VARCHAR (50) NOT NULL,
CONSTRAINT [PK_users] PRIMARY KEY ([phone_number])
);
之后,当我尝试添加下表时,我收到错误:
批处理执行时发生错误
CREATE TABLE [dbo].[location] (
[location_id] INT NOT NULL PRIMARY KEY IDENTITY (1, 1),
[sender] VARCHAR (50) NOT NULL,
[reciever] VARCHAR (50) NOT NULL,
[latitude] FLOAT (53) NOT NULL,
[longitude] FLOAT (53) NOT NULL,
CONSTRAINT [FK_1] FOREIGN KEY ([sender]) REFERENCES [dbo].[users] ([phone_number]) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT [FK_2] FOREIGN KEY ([reciever]) REFERENCES [dbo].[users] ([phone_number]) ON DELETE CASCADE ON UPDATE CASCADE
);
创建更新脚本时没有出现警告,并且数据库中也没有数据。我尝试从头开始重新创建所有内容,但错误仍然存在。我可能做错了什么?
编辑:如果我同时删除" ON DELETE CASCADE"则错误消失和" ON UPDATE CASCADE"从任何一个外键约束中,删除任何其他组合都没有帮助。那些限制有什么不对?
答案 0 :(得分:2)
鉴于MSDN上有关Msg 1785
的文档您收到此错误消息,因为在SQL Server中,表不能 在所有级联参照的列表中出现不止一次 由DELETE或UPDATE语句启动的操作。 例如,级联引用操作树必须只有 级联引用操作的特定表的一个路径 树。
及其陈述的解决方法
您可以通过多种方式强制实施参照完整性。陈述 参考完整性(DRI)是最基本的方式,但它也是 最灵活的方式。如果你需要更多的灵活性,但你仍然想要一个 高度完整性,你可以使用触发器
我们可以选择以这种方式避免这个问题创建TRIGGER
ALTER TRIGGER [dbo].[CascadeDeleteNumber]
ON [dbo].[users]
INSTEAD OF DELETE
AS
BEGIN
SET NOCOUNT ON;
DELETE FROM location WHERE Sender = (select phone_number from deleted)
DELETE FROM location WHERE Reciever = (select phone_number from deleted)
DELETE FROM users WHERE phone_number = (select phone_number from deleted)
END
DELETE触发器是一个INSTEAD OF,因为AFTER触发器永远不会被检查参照完整性所阻止。 INSTEAD OF允许我们先删除位置表中的记录,然后删除users表中的记录,使参照完整性快乐
对于UPDATE我们可以使用另一个TRIGGER,但它更棘手 我没有找到正确更新phone_number的方法而不破坏引用完整性,因此我设法更改phone_number暂时删除引用完整性,更新所需记录,然后重新引用参照完整性。
ALTER TRIGGER [dbo].[CascadeUpdateNumber]
ON [dbo].[users]
INSTEAD OF UPDATE
AS
BEGIN
SET NOCOUNT ON;
DECLARE @old_num nvarchar(50)
DECLARE @new_num nvarchar(50)
DECLARE @new_name varchar(50)
DECLARE @new_img varchar(50)
DECLARE @new_pwd varchar(50)
SELECT @old_num = phone_number FROM deleted
SELECT @new_num = phone_number, @new_name = name, @new_img = picture,
@new_pwd = password FROM inserted
ALTER TABLE [dbo].[location] DROP CONSTRAINT [FK_1]
ALTER TABLE [dbo].[location] DROP CONSTRAINT [FK_2]
UPDATE location SET sender = @new_num WHERE sender = @old_num
UPDATE location SET reciever = @new_num WHERE reciever = @old_num
UPDATE users SET phone_number = @new_num, name = @new_name,
picture=@new_img, password=@new_pwd
WHERE phone_number = @old_num
ALTER TABLE [dbo].[location] WITH CHECK
ADD CONSTRAINT [FK_3] FOREIGN KEY([sender])
REFERENCES [dbo].[users] ([phone_number])
ALTER TABLE [dbo].[location] WITH CHECK
ADD CONSTRAINT [FK_4] FOREIGN KEY([reciever])
REFERENCES [dbo].[users] ([phone_number])
END
从表格上的并发更新的角度来看,我不知道这种方法是否安全。
答案 1 :(得分:1)
我在SSMS中执行代码时遇到此错误。我做了一个快速搜索,有很多关于这个主题的信息供你研究。
消息1785,级别16,状态0,行2引入FOREIGN KEY约束 ' FK_2'在桌子上的位置'可能会导致循环或多个级联路径。 指定ON DELETE NO ACTION或ON UPDATE NO ACTION,或修改其他 FOREIGN KEY约束。 Msg 1750,Level 16,State 0,Line 2不能 创建约束或索引。查看以前的错误。
基于聊天的编辑:
我认为根据您删除位置的愿望,如果您这样做,那将是最好的。保持FK的完整性,并可能创建一个删除用户的存储过程