2010-10-12 17 views
4

Dans le tableau suivant, existe-t-il un moyen de garantir que PreviousID référence toujours un ID dans une rangée avec un ParentID correspondant ou, si ParentID est null, il est également null dans la ligne référencée?Clé étrangère composée avec colonne nullable

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

Un exemple:

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

est-il un moyen de faire respecter cela?

MISE À JOUR: Pour ceux qui se demandent, le composé clé étrangère n'applique pas pour la raison suivante (copié à partir MSDN):

Une contrainte FOREIGN KEY peut contenir des valeurs nulles; Toutefois, si une colonne d'une contrainte composite FOREIGN KEY contient des valeurs NULL, la vérification de toutes les valeurs qui constituent la contrainte FOREIGN KEY est ignorée. Pour vous assurer que toutes les valeurs d'une contrainte composite FOREIGN KEY sont vérifiées, spécifiez NOT NULL sur toutes les colonnes participantes.

UPDATE: Dans le cas où il permet de visualiser la structure de données étant représentée, il est un arbre B, où les noeuds ayant le même parent composer une liste liée. J'essaye de faire en sorte que chaque pointeur 'précédent' dans la liste liée pointe vers un autre noeud avec le même parent. Dans le cas où le parent est null, il doit pointer vers un autre nœud où le parent est également nul.

+0

Triggers? Il n'appliquera pas, mais peut vous aider à le gérer. –

+0

Et à quelle valeur ID dans MyTable doit ParentID NULL référence? –

+0

Lorsqu'il existe une valeur, ParentID doit référencer ParentID. Quand il n'y en a pas, eh bien ... c'est le problème que j'aimerais résoudre. Comme une clé étrangère composée ne fait pas l'affaire, je cherche d'autres options. – Daniel

Répondre

0

Essayez ceci:

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

Résultats:

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

Cela empêche simplement les nœuds avec des parents nuls d'être liés. Il ne nécessite pas que PreviousID se réfère à un autre nœud avec un parent nul. – Daniel

+0

Ce que je fais habituellement pour une contrainte complexe est de créer une fonction qui prend les valeurs de relivant pour la nouvelle ligne et retourne un booléen indiquant si la condition est remplie, puis appelle cette fonction à partir d'une contrainte de vérification. Cela ferait ce que vous voulez pour ce système. J'écrirais la fonction moi-même, mais je dois avouer que je suis un peu peu inspiré par la forme des données. Je ne vois pas vraiment ce que vous essayez d'accomplir. Pour créer un arbre B réel, il faudrait une mémoire à accès direct indexée ou un accès au disque. Une base de données possède déjà des structures de données sophistiquées. Je ne comprends pas. –

+0

L'utilisation des fonctions définies par l'utilisateur dans les contraintes de vérification a [intégrité] (https://connect.microsoft.com/SQLServer/feedback/details/301828#details) et [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), mais il peut s'agir d'une option en dernier recours. Les structures de données telles que les arbres b, les listes chaînées, etc. sont souvent modélisées en tant que tables de base de données. Il existe toutes sortes de raisons pour stocker des données dans une base de données plutôt que directement sur le disque, la plus importante étant l'intégrité référentielle. – Daniel