SQL 唯一约束允许违反空值

SQL Unique Constraint allows violation with nulls

我有一个 table,它在 3 列上有一个非聚集的唯一索引,"MenuId"、"Name" 和 "ParentId"。

问题是,当 ParentId 设置为 NULL 时,我可以向此 table 中插入多行,如下所示。

如果我尝试添加重复行并且 ParentId 不为空,则唯一约束会按预期工作。

我对唯一索引的理解是,它只允许参与索引的列的单个唯一组合,所以我希望下图中能够插入第一行,但它应该抛出插入第二(和第三)行时违反索引的异常 - 但它没有。

我哪里错了?

我正在使用 SQL LocalDb。

更新:我正在使用 EF Core 从代码生成数据库,似乎在这种情况下,正在使用 WHERE 子句创建唯一约束以在 ParentId 或 Name 为 NULL 时忽略:

CREATE UNIQUE NONCLUSTERED INDEX [IX_MenuItem_MenuId_ParentId_Name]
    ON [dbo].[MenuItem]([MenuId] ASC, [ParentId] ASC, [Name] ASC) 
WHERE ([ParentId] IS NOT NULL AND [Name] IS NOT NULL);

令人尴尬的是,当我在 SQL 服务器资源管理器属性 window 中探索唯一约束时,这个 WHERE 子句并不明显 - 我只是检查了唯一约束存在,并且我的列expected where included - 但这还不够。感谢下面的评论员,他无法重现并让我实际检查脚本以查找此 WHERE 子句变得明显的索引。我现在已将我的问题转移到一个与 EF 为什么在我的案例中产生这个问题有关的问题: https://github.com/aspnet/EntityFrameworkCore/issues/17586

将-1设置为默认值ParentId
或者

ALTER TABLE TableName 
ADD CONSTRAINT cUniq UNIQUE (MenuId,Name,ParentId);

感谢@萧为元提示我更详细地查看 Unique 约束,而不仅仅是属性 window!

UNIQUE 索引有一个 WHERE 子句,导致它忽略父 ID 或名称具有 NULL 值的记录:

CREATE UNIQUE NONCLUSTERED INDEX [IX_MenuItem_MenuId_ParentId_Name]
    ON [dbo].[MenuItem]([MenuId] ASC, [ParentId] ASC, [Name] ASC) 
WHERE ([ParentId] IS NOT NULL AND [Name] IS NOT NULL);

这是由 EF 生成的 - 这就是你在依赖 ORM 为你做事并假设他们做你想做的事情时遇到的问题 - 拍打自己的手腕