J'ai une table où les lignes peuvent être liées les unes aux autres, et logiquement, la relation va dans les deux sens (essentiellement, est sans direction) entre les deux lignes. (Et si vous vous demandez, oui, cela devrait vraiment être une seule table. Ce sont deux choses exactement de la même entité / type logique.) Je peux penser à deux façons de représenter cela:
- Conserver la relation et son inverse
- Stockez la relation dans un sens, empêchez la base de données de la stocker dans l'autre sens et ayez deux index avec des ordres opposés pour les FK (un index étant l'index PK)
- Stockez la relation dans un sens avec deux index et laissez le deuxième être inséré de toute façon (ça sonne un peu dégoûtant, mais bon, exhaustivité)
- Créez une sorte de table de regroupement et ayez un FK sur la table d'origine. (Cela soulève beaucoup de questions. La table de regroupement n'aurait qu'un nombre; pourquoi même la table? Rendre FK NULLable ou avoir des groupes avec une seule ligne associée?)
Quels sont les principaux avantages et inconvénients de ces moyens, et bien sûr, y a-t-il un moyen auquel je n'ai pas pensé?
Voici un SQLFiddle avec lequel jouer: http://sqlfiddle.com/#!12/7ee1a/1/0 . (Il se trouve que c'est PostgreSQL car c'est ce que j'utilise, mais je ne pense pas que cette question soit très spécifique à PostgreSQL.) Il stocke actuellement à la fois la relation et son inverse à titre d'exemple.
la source
Réponses:
Ce que vous avez conçu est bon. Ce qui doit être ajouté est une contrainte pour rendre la relation sans direction. Ainsi, vous ne pouvez pas avoir de
(1,5)
ligne sans qu'une(5,1)
ligne ne soit également ajoutée.Cela peut être accompli * avec une contrainte d'auto-référencement sur la table de bridge.
*: cela peut être accompli dans Postgres, Oracle, DB2 et tous les SGBD qui ont implémenté des contraintes de clé étrangère comme le décrit le standard SQL (différé, par exemple vérifié à la fin de la transaction.) La vérification différée n'est pas vraiment nécessaire de toute façon, comme dans SQL- Serveur qui les vérifie à la fin de l'instruction et cette construction fonctionne toujours. Vous ne pouvez pas le faire dans MySQL car "InnoDB vérifie les contraintes UNIQUE et FOREIGN KEY ligne par ligne" .
Ainsi, dans Postgres, les éléments suivants répondront à vos besoins:
Testé sur: SQL-Fiddle
Si vous essayez d'ajouter une ligne
(1,5)
:Il échoue avec:
De plus, vous pouvez ajouter une
CHECK
contrainte si vous souhaitez interdire des(y,y)
lignes:Il existe d'autres façons de l'implémenter comme vous le mentionnez, comme le stockage d'une seule direction de la relation (dans une ligne, pas deux) en forçant l'ID inférieur dans
x_id1
et l'ID supérieur dans lax_id2
colonne. Il semble plus facile à implémenter, mais conduit généralement à des requêtes plus complexes plus tard:la source