允许多个NULLS的UNIQUE 'WHERE'索引可以用作外键关系的主键吗?

Can a UNIQUE 'WHERE' index which allows multiple NULLS be used as the primary key for a foreign key relationship?

在 Azure 上使用 SQL 服务器:12.0.2000.8

我已经为 TablePrimary 定义了以下唯一索引:

CREATE UNIQUE NONCLUSTERED INDEX [IX_TablePrimary_Id] 
ON [dbo].[TablePrimary] ([PrimaryId] ASC)
WHERE [PrimaryId] IS NOT NULL

WHERE子句允许多行在该列中有NULL,但该列中的每个非NULL值必须是唯一的。

TablePrimary 中的索引列应该是 suitable 作为与 TableForeign 的外键关系的主键吗?每个非 NULL 值都必须是唯一的,并且外部 table 中的 NULL 无论如何都不会创建外键关系。但是我在尝试将外键关系放在 TableForeign.

上时遇到错误

Unable to create relationship 'FK_TableForeign_TablePrimary'.
There are no primary or candidate keys in the referenced table 'dbo.TablePrimary' that match the referencing column list in the foreign key 'FK_TableForeign_TablePrimary'.

在我深入研究之前,我想验证我正在尝试做的事情确实可行。基本上,并非 TablePrimary 中的每一行都会在 TableForeign 中有子项。但是 TableForeign 中确实存在的那些行必须在 TablePrimary 中有匹配的 PrimaryId (还有其他方法可以完成工作,但在这种情况下,我需要第三个 table 作为 TablePrimaryTableForeign 之间的交叉引用,如果没有必要,我想避免这种情况,尽管如果有必要,那么它就是必要的)。

Can a UNIQUE 'WHERE' index which allows multiple NULLS be used as the primary key for a foreign key relationship?

没有。唯一过滤索引不能被外键引用。 唯一索引(即使包含列,虽然没有过滤器)可以被外键引用。

编辑:可空性。外键可以引用具有 NULLable 列的唯一 indexes/constraints。可为空性不是创建外键的先决条件。但是,不会检查任何 fk 列中至少有一个空值的行的外键:

create table dbo.parent
(
id1 int null,
id2 int null,
constraint id1id2 unique(id1, id2)
);

insert into dbo.parent(id1, id2)
values(1, 1), (2, 2), (3, null);

go

create table dbo.child
(
childid int identity,
parentid1 int,
parentid2 int,
constraint fkparent foreign key(parentid1, parentid2) references parent(id1, id2)
)
go


insert into dbo.child(parentid1, parentid2)
values (1, 1), (2, 2) --ok
go

insert into dbo.child(parentid1, parentid2)
values (4, 4) -- fk violation, there is no 4,4 parent row
go

insert into dbo.child(parentid1, parentid2)
values (3, null) --do not get tricked here.... because the fk has a null value, the fk is NOT checked at all
go

--fk with one null value, fk is not checked at all 
insert into dbo.child(parentid1, parentid2)
values (100, null) -- but there is no 100, null parent row
go

select *
from parent;
select *
from child;