Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Compound foreign key with nullable column

In the following table, is there a way to ensure PreviousID always references an ID in a row with a matching ParentID, or, if ParentID is null, it is also null in the referenced row?

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)
)

An example:

+-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
+----+----------+------------+  

Is there a way to enforce this?

UPDATE: For those wondering, the compound foreign key doesn't enforce this for the following reason (copied from MSDN):

A FOREIGN KEY constraint can contain null values; however, if any column of a composite FOREIGN KEY constraint contains null values, verification of all values that make up the FOREIGN KEY constraint is skipped. To make sure that all values of a composite FOREIGN KEY constraint are verified, specify NOT NULL on all the participating columns.

UPDATE: In case it helps to visualize the data structure being represented, it's a B-tree where nodes having the same parent compose a linked list. I'm trying to enforce that each 'previous' pointer in the linked list points to another node with the same parent. In the case that the parent is null, it should point to another node where the parent is also null.

like image 515
Daniel Avatar asked Oct 12 '10 20:10

Daniel


People also ask

Can you have a foreign key on a nullable field?

A table can have many foreign keys. A foreign key is nullable if any part is nullable. A foreign key value is null if any part is null.

Can you have a foreign key constraint on a nullable column?

Yes, a foreign key can be null. When a foreign key's value is not known at the time of record generation then it's kept null, given that that column is created nullable (default value is null).

Can composite foreign key be null?

A FOREIGN KEY constraint can contain null values; however, if any column of a composite FOREIGN KEY constraint contains null values, verification of all values that make up the FOREIGN KEY constraint is skipped.

Can a foreign key be a compound?

A composite foreign key is a foreign key that consists of two or more columns. It is important to note that all the columns in a single foreign key must point to the same table. In other words, it is not possible to have a foreign key that references to a column in Table 1 and a column in Table 2.


1 Answers

Try this:

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 */
) 

Results:

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. */
like image 110
Jeffrey L Whitledge Avatar answered Sep 23 '22 17:09

Jeffrey L Whitledge