唯一索引上的外键不适用于NULL列

时间:2022-03-04 10:08:18

I am struggling with a foreign key on a unique index in SQL Server, which isn't quite working as expected.

我在SQL Server中的一个唯一索引上使用外键时遇到了困难,这个索引并没有按预期工作。

My table structure is like this:

我的表结构是这样的:

  • Table mm1 has a nonclustered PK-Index on a surrogate key column id
    • Additionally mm1 has a clustered unique index on three columns (one of them is nullable)
    • 另外mm1在三列上有一个聚簇唯一索引(其中一列可以为空)

    • Table mm2 links on those three columns via a foreign key
    • 表mm2通过外键链接这三列

  • 表mm1在代理键列id上具有非聚簇PK-Index另外mm1在三列上有一个聚簇唯一索引(其中一列可以为空)表mm2通过外键在这三列上链接

The creation of these objects doesn't throw any errors. However, the foreign key is not evaluted properly and allows for non-existing values in mm1 to be inserted in mm2. This seems to be related on the nullable column c....if I set the foreign key on just columns a and b it works as expected.

创建这些对象不会产生任何错误。但是,外键未正确评估,并允许将mm1中的不存在值插入mm2中。这似乎与可空列c相关....如果我只在列a和b上设置外键它按预期工作。

Can you explain this behaviour? Why allowing to define a unique index including null in the first place but not supporting it properly in foreign key constraints? Is there a way to achieve correct results without changing contents of table mm2?

你能解释一下这种行为吗?为什么允许首先定义一个包含null的唯一索引,但在外键约束中不能正确支持它?有没有办法在不改变表格mm2的内容的情况下获得正确的结果?

Here's a little repro script:

这是一个小的repro脚本:

CREATE table mm1 (
    id int identity(1,1) NOT NULL,
    a varchar(50) not null,     
    b int not null, 
    c int null, 
    PRIMARY KEY NONCLUSTERED(id))

CREATE table mm2 (
    id int identity(1,1) NOT NULL,
    a varchar(50) not null,
    b int not null,
    c int null,
    d varchar(10),
    PRIMARY KEY NONCLUSTERED(id))

CREATE  UNIQUE CLUSTERED INDEX  idx_mm1_mm_fkTest1 ON mm1(a,b,c)

ALTER TABLE mm2
ADD CONSTRAINT  fk_mm2_mm_fkTest1 
FOREIGN KEY (a,b, c)  REFERENCES mm1(a,b,c)

ALTER TABLE mm2 CHECK CONSTRAINT fk_mm2_mm_fkTest1;

INSERT INTO mm1 VALUES ('abc', 1, 2);

INSERT INTO mm2 
(a,b,d) VALUES('sa',1,'sad')

SELECT * FROM mm2;

1 个解决方案

#1


2  

I am not at all sure what I would expect this to do. The more I think about it, the less sense it makes.

我完全不确定我会期待这件事。我想的越多,它的意义就越小。

NULL is evaluated in these contexts to mean UNKNOWN. With an unknown in a foreign key you can never be sure which row it refers to in the first place. In other words, this constraint makes no semantic sense.

在这些上下文中计算NULL表示UNKNOWN。对于外键中的未知,您可能永远无法确定它首先引用哪一行。换句话说,这种约束没有语义意义。

Use a default value and have your foreign key hit non-null values only. If you allow NULLs in foreign keys they will be dangling anyway.

使用默认值并使外键仅命中非空值。如果在外键中允许NULL,则无论如何都会悬空。

#1


2  

I am not at all sure what I would expect this to do. The more I think about it, the less sense it makes.

我完全不确定我会期待这件事。我想的越多,它的意义就越小。

NULL is evaluated in these contexts to mean UNKNOWN. With an unknown in a foreign key you can never be sure which row it refers to in the first place. In other words, this constraint makes no semantic sense.

在这些上下文中计算NULL表示UNKNOWN。对于外键中的未知,您可能永远无法确定它首先引用哪一行。换句话说,这种约束没有语义意义。

Use a default value and have your foreign key hit non-null values only. If you allow NULLs in foreign keys they will be dangling anyway.

使用默认值并使外键仅命中非空值。如果在外键中允许NULL,则无论如何都会悬空。