具有可空列的复合外键

时间:2010-10-12 20:48:00

标签: sql-server foreign-keys referential-integrity

在下表中,是否有办法确保PreviousID始终引用具有匹配ParentID的行中的ID,或者,如果ParentID为null,则在引用的行中它也为null?

CREATE TABLE MyTable (
  ID int not null identity(1,1) primary key,
  ParentID int null foreign key references MyTable (ID),
  PreviousID int null foreign key reference MyTable (ID),
    foreign key (ParentID, PreviousID) references MyTable (ParentID, ID)
)

一个例子:

+-ID-+-ParentID-+-PreviousID-+  
|  1 |   NULL   |    NULL    |  
|  2 |     1    |    NULL    |  
|  3 |   NULL   |      2     | <-- shouldn't be possible, should have to refer to ID where ParentID is null
+----+----------+------------+  

有没有办法强制执行此操作?

更新:对于那些想知道的人,复合外键不会强制执行此操作,原因如下(从MSDN复制):

  

FOREIGN KEY约束可以包含空值;但是,如果复合FOREIGN KEY约束的任何列包含空值,则会跳过对构成FOREIGN KEY约束的所有值的验证。要确保验证复合FOREIGN KEY约束的所有值,请在所有参与列上指定NOT NULL。

UPDATE :如果它有助于可视化所表示的数据结构,它就是一个B树,其中具有相同父节点的节点组成一个链表。我试图强制链表中的每个“前一个”指针指向具有相同父节点的另一个节点。在父项为null的情况下,它应该指向父项也为空的另一个节点。

1 个答案:

答案 0 :(得分:0)

试试这个:

CREATE TABLE MyTable ( 
  ID int not null identity(1,1) primary key, 
  ParentID int null foreign key references MyTable (ID), 
  PreviousID int null foreign key references MyTable (ID), 
    foreign key (ParentID, PreviousID) references MyTable (ParentID, ID),
    unique (ParentID, ID),  /* Required for foreign key */
  check (PreviousID is null or ParentID is not null)  /* enforeces requested constraint */
) 

结果:

insert into MyTable (ParentID, PreviousID) values (null, null) /* (1 row(s) affected) */
insert into MyTable (ParentID, PreviousID) values (1, null) /* (1 row(s) affected) */
insert into MyTable (ParentID, PreviousID) values (null, 2) /* The INSERT statement conflicted with the CHECK constraint. 
    The statement has been terminated. */