Pourquoi les clés étrangères composites ont-elles besoin d'une contrainte unique distincte?

10

Voici un tableau simple où les enregistrements peuvent référencer les enregistrements parents dans le même tableau:

CREATE TABLE foo (
    id         SERIAL  PRIMARY KEY,
    parent_id  INT     NULL,
    num        INT     NOT NULL,
    txt        TEXT    NULL,
    FOREIGN KEY (parent_id) REFERENCES foo(id)
);

Avec l'exigence supplémentaire que l'une des autres valeurs de champ ( num) doit être identique entre les enregistrements parent et enfant, j'ai pensé qu'une clé étrangère composite devrait faire l'affaire. J'ai changé la dernière ligne en

    FOREIGN KEY (parent_id, num) REFERENCES foo(id, num)

et obtenu ERREUR: il n'y a pas de contrainte unique correspondant aux clés données pour la table référencée "foo" .

Je peux facilement ajouter cette contrainte, mais je ne comprends pas pourquoi elle est nécessaire, alors qu'une des colonnes référencées ( id) est déjà garantie d'être unique? D'après moi, la nouvelle contrainte serait redondante.

Zilk
la source

Réponses:

11

C'est une limitation du SGBD - pour autant que je sache. Et pas seulement lors de l'ajout d'une colonne mais également lors de la réorganisation des colonnes. Si nous avons une UNIQUEcontrainte (a1, a2), nous ne pouvons pas ajouter un FOREIGN KEYça à REFERENCES (a2, a1)moins qu'il n'y ait une contrainte unique sur ce (a2, a1)qui est essentiellement redondante.

Il ne serait pas terriblement difficile d'ajouter ceci en tant que fonctionnalité:

En cas de UNIQUEcontrainte (a), tout (a, b, c, ..., z)ou (b,c, ...a, ...z)combinaison est également garanti UNIQUE.

ou la généralisation:

En cas de UNIQUEcontrainte (a1, a2, ..., aN), toute (a1, a2, ..., aN, b1, b2, ..., bM)combinaison ou tout réarrangement est également garanti UNIQUE.

Il semble qu'il n'ait pas été demandé ou qu'il n'ait pas été jugé suffisamment prioritaire pour être mis en œuvre.

Vous pouvez toujours faire une demande - dans le canal respectif - pour que la fonctionnalité soit implémentée. Ou même l'implémenter vous-même, si le SGBD est open source, comme Postgres.

ypercubeᵀᴹ
la source
Je ne suis pas sûr que ce serait aussi simple que cela. Qu'en est-il des index partiels ou des valeurs NULL? etc. NULL peut toujours fonctionner correctement si vous êtes satisfait NULL != NULL. Quoi qu'il en soit .. :)
Joishi Bodio
@JoishiBodio Je ne pense pas que les Nulls soient un problème. Les contraintes UNIQUES peuvent également être définies ou des colonnes annulables. La valeur par défaut est que si une colonne a une valeur NULL, la contrainte est transmise et la ligne acceptée.
ypercubeᵀᴹ
Cependant, si a1, a2, ... aN ne sont pas annulables et b1, b2, bM, nous pouvons avoir des problèmes. Mais la fonctionnalité pourrait sûrement être implémentée pour les colonnes non nulles. Ce qui est probablement inquiétant, ce sont les implications en termes d'efficacité.
ypercubeᵀᴹ du
Je sais UNIQUE INDEXoù sont les colonnes NULLABLE.. c'est pourquoi je l'ai mentionné. :) Mais je suis d'accord - dans le cas où il n'y a pas de NULL (et pas d'index partiel non plus), c'est probablement assez simple.
Joishi Bodio
5

Les clés étrangères en général (pas seulement composites) DOIVENT pointer vers une CLÉ UNIQUE d'une certaine sorte dans une autre table. Sinon, il n'y aurait pas d'intégrité des données relationnelles.

Cela se plaint car, alors que vous avez une clé unique sur (id) .. vous n'avez PAS de clé unique sur (id, num) .. Ainsi, en ce qui concerne la base de données, la paire (id, num) est pas GARANTI d'être unique. Nous, en tant qu'humains, pouvons comprendre que ce sera unique, mais je suis sûr qu'il y aurait beaucoup de code supplémentaire qu'ils devraient ajouter pour rendre Postgres assez intelligent pour voir que "oh hé .. id est censé être unique , donc id, num doit également être unique "..

Je serais très surpris s'ils ajoutaient ce code lorsque tout ce que vous avez à faire est de créer un autre index unique sur les deux colonnes pour résoudre le problème.

Juste pour être clair, le code qu'ils devraient ajouter ne serait pas seulement ce cas simple ... il devrait gérer tous les cas, même ceux où la clé étrangère est sur 4+ colonnes, etc. Je suis sûr la logique serait assez complexe.

Joishi Bodio
la source