2010-10-12 97 views
4

在下表中,有沒有一種方法可以確保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 
+----+----------+------------+ 

有沒有辦法強制執行呢?

UPDATE:對於那些想知道,化合物外鍵不執行此由於以下原因(來自MSDN複製):

外鍵約束可以包含空值;但是,如果複合FOREIGN KEY約束的任何列包含空值,則會跳過組成FOREIGN KEY約束的所有值的驗證。要確保複合FOREIGN KEY約束的所有值都已驗證,請在所有參與的列上指定NOT NULL。

UPDATE:如果它有助於可視化數據結構表示,這是一個B-樹,其中具有相同父節點構成一個鏈表。我試圖強制鏈接列表中的每個'previous'指針指向具有相同父項的另一個節點。在父項爲空的情況下,它應指向父項也爲空的另一個節點。

+0

觸發器?它不會執行,但可以幫助您管理它。 – 2010-10-12 21:21:45

+0

並且MyTable中的哪個值ID應該是ParentID NULL引用? – 2010-10-13 10:14:08

+0

當存在值時,ParentID應引用ParentID。如果沒有,那麼......這是我想解決的問題。由於複合外鍵不能實現這個功能,我正在尋找其他選項。 – Daniel 2010-10-13 14:29:02

回答

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. */ 
+0

這只是防止具有空父母的節點被鏈接。它不要求PreviousID引用具有空父代的另一個節點。 – Daniel 2010-10-13 18:56:22

+0

我通常對一個複雜的約束做的事情是創建一個函數,該函數接受新行的relivant值,並返回一個指示條件是否滿足的布爾值,然後從檢查約束中調用該函數。這將做你想要的這個系統。我會自己寫這個函數,但我必須承認,我對數據的形式沒有一點啓發。我真的不明白你想要完成什麼。要製作真正的B樹需要索引直接訪問內存或磁盤訪問。一個DB已經有了複雜的數據結構。我不明白。 – 2010-10-13 20:34:14

+0

UDF在檢查約束中的使用具有[integrity](https://connect.microsoft.com/SQLServer/feedback/details/301828#details)和[performance](http://sqlblog.com/blogs/alexander_kuznetsov/archive /2009/06/25/scalar-udfs-wrapped-in-check-constraints-are-very-slow-and-may-fail-for-multirow-updates.aspx)問題,但它可能是一個選項,作爲最後一個採取。數據結構(如b樹,鏈接列表等)通常建模爲數據庫表。將數據存儲在數據庫中而不是直接存儲到磁盤的原因各不相同,其中最突出的是參照完整性。 – Daniel 2010-10-14 15:48:06