Using SQL Server on Azure: 12.0.2000.8
I've defined the following unique index for TablePrimary
:
CREATE UNIQUE NONCLUSTERED INDEX [IX_TablePrimary_Id]
ON [dbo].[TablePrimary] ([PrimaryId] ASC)
WHERE [PrimaryId] IS NOT NULL
The WHERE
clause allows multiple rows to have NULL
in this column, but every non-NULL value in this column must be unique.
Should the indexed column in TablePrimary
be suitable as the primary key for a foreign key relationship to TableForeign
? Every non-NULL value must be unique and NULL in the foreign table wouldn't create a foreign key relationship anyway. But I am getting an error trying to place the foreign key relationship on 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'.
Before I dig deeper into this, I'd like to verify that what I am trying to do is indeed possible. Basically, not every row in TablePrimary
will have children in TableForeign
. But those rows which do exist in TableForeign
must have a matching PrimaryId
in TablePrimary
(there are other ways to get the job done but in this case, I'd need a third table as the cross-ref between TablePrimary
and TableForeign
and I'd like to avoid that if it's not necessary, although, if it is necessary, then it is necessary).
Can a UNIQUE 'WHERE' index which allows multiple NULLS be used as the primary key for a foreign key relationship?
No. Unique filtered indexes cannot be be referenced by foreign keys. Unique indexes (even with included columns, no filters though) can be referenced by foreign keys.
edit: for Nullability. Foreign keys can reference unique indexes/constraints with NULLable columns. Nullability is not a prerequisite for creating foreign keys. However, foreign keys are NOT checked for rows with at least one null value in any of the fk columns:
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;