MSSQL约束可能导致循环或多个级联路径[重复]

Posted

技术标签:

【中文标题】MSSQL约束可能导致循环或多个级联路径[重复]【英文标题】:MSSQL Constraint may cause cycles or multiple cascade paths [duplicate] 【发布时间】:2015-05-22 12:43:24 【问题描述】:

我有这样一个场景:

User 可以拥有多个AccountsUser 也有比特币地址(他自己输入的),它们是“提现地址”。每个Account 也可能有多个比特币地址(即“存款地址”)。

所有地址都在一个表中,唯一的区别是存款/取款仅由表BitcoinAddresses中的列Type指定。

我想创建一个场景,删除User会导致他拥有的所有提款BitcoinAddresses被删除,同时他拥有的所有Accounts也被删除。但是删除Account 应该会导致BitcoinAddresses 引用设置为NULL

我尝试过类似的方法:

CREATE TABLE [dbo].[Users] (
    [Id]                 NVARCHAR (128) NOT NULL,
    [UserName]           NVARCHAR (64)  NULL,
    CONSTRAINT [PK_dbo.Users] PRIMARY KEY CLUSTERED ([Id] ASC),
);

CREATE TABLE [dbo].[Accounts] (
    [Id]       BIGINT         IDENTITY (1, 1) NOT NULL,
    [UserId]   NVARCHAR (128) NOT NULL,
    [Number] BIGINT         NOT NULL,
    CONSTRAINT [PK_dbo.Accounts] PRIMARY KEY CLUSTERED ([Id] ASC),
    CONSTRAINT [FK_dbo.Accounts.Users_UserId] FOREIGN KEY ([UserId]) REFERENCES [dbo].[Users] ([Id]) ON DELETE CASCADE
);

CREATE TABLE [dbo].[BitcoinAddresses] (
    [BitcoinAddressId] INT            IDENTITY (1, 1) NOT NULL,
    [Address]          NVARCHAR (MAX) NOT NULL,
    [AccountId]     BIGINT         NULL,
    [UserId]           NVARCHAR (128) NULL,
    [Type]            NVARCHAR (MAX) NULL,
    CONSTRAINT [PK_dbo.BitcoinAddresses] PRIMARY KEY CLUSTERED ([BitcoinAddressId] ASC),
    CONSTRAINT [FK_dbo.BitcoinAddresses_dbo.Accounts_AccountId] FOREIGN KEY ([AccountId]) REFERENCES [dbo].[Accounts] ([Id]) ON DELETE SET NULL,
    CONSTRAINT [FK_dbo.BitcoinAddresses_dbo.Users_UserId] FOREIGN KEY ([UserId]) REFERENCES [dbo].[Users] ([Id]) ON DELETE CASCADE
);

此解决方案会导致错误:

Introducing FOREIGN KEY constraint 'FK_dbo.BitcoinAddresses_dbo.Users_UserId' on table 'BitcoinAddresses' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.

但显然我在这种方法中看不到任何循环。你能向我解释为什么会发生这种行为吗?我该如何解决?我想指出,我不想将提款和存款地址拆分为两个不同的表(因为这将是这种情况下的正确解决方案,但我想知道为什么我不能创建此类引用)

这是我的小提琴:http://sqlfiddle.com/#!6/5d9cd

【问题讨论】:

您的设计还有一个问题。 BitcoinAddresses 中的一行可以引用 User 和具有不同 UserIds 的 Account。这是故意的吗?如果没有,您可以删除 2 个 FK 并仅使用一个,使用:FOREIGN KEY (UserId, AccountId) REFERENCES [dbo].[Accounts] (UserId, Id),您将能够解决您的两个问题 ;) 哦,您需要在 Accounts 中添加一个 UNIQUE 约束上面要定义的FK。 将表格一分为二似乎是最好的解决方案。一个只需要用户的 FK(并且没有 AccountID 列),另一个只需要 Accounts。没有多个级联路径和较少可为空的列。 感谢您的建议。我知道我可以将它分成两个表,尽管在我的情况下这并不容易,因为整个场景都是由实体框架管理的。因此,该框架确保我没有遇到在一个BitcoinAddress 上有不同的AccountUser 的情况。但是感谢您的关注,好消息! 【参考方案1】:

如果您删除用户,他的帐户将被删除,而他的 bitcoinaddresses 将被删除。但是当他的account被删除时,该帐户的bitcoinaddresses也将更新为NULL。这对 SQL Server 来说太复杂了。它需要级联链简单整洁,而不是分支和/或收敛。如果用户删除会导致比特币被删除并将其帐户设置为NULL,SQL-Server 怎么知道你想要哪个?

【讨论】:

你是对的,但即使我在每个 REFERENCE 上都将其设置为 CASCADE delete,它也会给我同样的错误。 是的,出于同样的原因。两条级联路径会聚。这是根本原因。 SQL 没有被编程为深入思考聚合级联是否真的会导致问题。如果它发现潜在的收敛,则会引发错误。 @TabAlleman 请编辑您的 naswer,从“SQL”到“SQL-Server”。还有其他 SQL 产品(如 Postgres)可以与多个级联路径完美配合。 SQL-Server 架构师选择禁止这样做(出于某些充分的理由,没有争论)。 感谢@ypercube 的编辑。不幸的是,对我之前的评论进行相同的编辑为时已晚。

以上是关于MSSQL约束可能导致循环或多个级联路径[重复]的主要内容,如果未能解决你的问题,请参考以下文章

引入 FOREIGN KEY 约束可能会导致循环或多个级联路径 - 为啥?

SQL Server 引入 FOREIGN KEY 约束可能导致循环或多个级联路径

更新迁移到数据库时出错:外键约束可能导致循环或多个级联路径

错误:引入FOREIGN KEY约束可能会导致循环或多个级联路径

Entity Framework Core 5 - 在表上引入 FOREIGN KEY 约束可能会导致循环或多个级联路径

可能会导致循环或多个级联路径。指定ON DELETE NO ACTION或ON UPDATE NO ACTION,或修改其他FOREIGN KEY约束