web-dev-qa-db-fra.com

Pourquoi les correspondances de clé primaire / clé étrangère ne sont-elles pas utilisées pour les jointures?

Pour autant que je sache, de nombreux SGBD (par exemple mysql, postgres, mssql) n'utilisent les combinaisons fk et pk que pour limiter les modifications des données, mais ils sont rarement utilisés de manière native pour sélectionner automatiquement les colonnes à joindre (comme la jointure naturelle le fait avec les noms). Pourquoi donc? Si vous avez déjà défini une relation entre 2 tables avec un pk/fk, pourquoi la base de données ne peut-elle pas comprendre que si je joins ces tables, je veux les joindre sur les colonnes pk/fk?

EDIT: pour clarifier un peu ceci:

supposons que j'ai une table1 et une table2. table1 on a une clé étrangère sur la colonne a, qui fait référence à la clé primaire sur la table2, la colonne b. Maintenant, si je rejoins ces tables, je vais devoir faire quelque chose comme ceci:

SELECT * FROM table1
JOIN table2 ON table1.a = table2.b

Cependant, j'ai déjà défini à l'aide de mes clés que table1.a fait référence à table2.b, il me semble donc qu'il ne devrait pas être trop difficile de faire en sorte qu'un système SGBD utilise automatiquement table1.a et table2.b comme colonnes de jointure, de telle sorte que l'on peut simplement utiliser:

SELECT * FROM table1
AUTO JOIN table2

Cependant, de nombreux SGBD ne semblent pas implémenter quelque chose comme ça.

49
Tiddo

Dans de nombreux cas, il existe plusieurs façons de joindre deux tables; Voir les autres réponses pour de nombreux exemples. Bien sûr, on pourrait dire que ce serait une erreur d'utiliser la "jointure automatique" dans ces cas. Il ne restait alors qu'une poignée de cas simples où il pouvait être utilisé.

Cependant, il y a un grave inconvénient! Les requêtes qui sont correctes aujourd'hui, pourraient devenir une erreur demain simplement en ajoutant un deuxième FK à la même table!

Permettez-moi de le répéter: en ajoutant des colonnes, les requêtes qui n'utilisent pas ces colonnes pourraient passer de "correct" à "erreur"!

C'est un tel cauchemar de maintenance, que tout guide de style sain interdirait d'utiliser cette fonctionnalité. La plupart interdisent déjà select * pour la même raison!

Tout cela serait acceptable si les performances étaient améliorées. Mais ce n'est pas le cas.

En résumé, cette fonctionnalité ne peut être utilisée que dans un ensemble limité de cas simples, n'augmente pas les performances, et la plupart des guides de style interdisent quand même son utilisation.

Par conséquent, il n'est pas surprenant que la plupart des fournisseurs de bases de données choisissent de consacrer leur temps à des choses plus importantes.

32
Sjoerd

Une clé étrangère est censée contraindre les données. c'est-à-dire faire respecter l'intégrité référentielle. C'est ça. Rien d'autre.

  1. Vous pouvez avoir plusieurs clés étrangères vers la même table. Considérez ce qui suit lorsqu'un envoi a un point de départ et un point d'arrivée.

    table: USA_States
    StateID
    StateName
    
    table: Shipment
    ShipmentID
    PickupStateID Foreign key
    DeliveryStateID Foreign key
    

    Vous pouvez vous joindre en fonction de l'état de collecte. Vous souhaitez peut-être vous joindre à l'état de livraison. Vous souhaitez peut-être effectuer 2 jointures pour les deux! Le moteur SQL n'a aucun moyen de savoir ce que vous voulez.

  2. Vous croiserez souvent des valeurs scalaires de jointure. Bien que les scalaires soient généralement le résultat de calculs intermédiaires, vous aurez parfois une table spéciale avec exactement 1 enregistrement. Si le moteur essayait de détecter une clé foriegn pour la jointure ... cela n'aurait aucun sens car les jointures croisées ne correspondent jamais à une colonne.

  3. Dans certains cas spéciaux, vous vous joindrez à des colonnes où aucune n'est unique. Par conséquent, la présence d'un PK/FK sur ces colonnes est impossible.

  4. Vous pouvez penser que les points 2 et 3 ci-dessus ne sont pas pertinents car vos questions concernent le moment où EST une seule relation PK/FK entre les tables. Cependant, la présence d'un seul PK/FK entre les tables ne signifie pas que vous ne pouvez pas avoir d'autres champs à joindre en plus du PK/FK. Le moteur SQL ne saurait pas sur quels champs vous souhaitez vous joindre.

  5. Disons que vous avez une table "USA_States", et 5 autres tables avec un FK aux états. Les "cinq" tables ont également quelques clés étrangères les unes aux autres. Le moteur SQL doit-il joindre automatiquement les "cinq" tables avec "USA_States"? Ou doit-il joindre les "cinq" les uns aux autres? Tous les deux? Vous pouvez configurer les relations de sorte que le moteur SQL entre dans une boucle infinie en essayant de joindre des choses ensemble. Dans cette situation, il est impossible pour le moteur SQL de deviner ce que vous voulez.

En résumé: PK/FK n'a rien à voir avec les jointures de table. Ce sont des choses indépendantes indépendantes. C'est juste un accident de la nature que vous rejoignez souvent sur les colonnes PK/FK.

Souhaitez-vous que le moteur SQL devine s'il s'agit d'une jointure complète, gauche, droite ou interne? Je ne pense pas. Bien que ce serait sans doute un péché moindre que de deviner les colonnes à joindre.

27
Lord Tydus

le concept de "joignabilité". Relations r1 et r2 sont joignables si et seulement si les attributs avec le même nom sont du même type ... ce concept s'applique non seulement à la jonction en tant que telle mais aussi à diverses autres opérations [telles que l'union].

SQL et théorie relationnelle: comment écrire du code SQL précis par C.J. Date

SQL standard dispose déjà d'une telle fonctionnalité, connue sous le nom de NATURAL JOIN, et a été implémenté dans mySQL.

Bien que votre suggestion ne soit pas aussi valable, elle semble raisonnable. Avec SQL Server (qui manque de prise en charge de NATURAL JOIN ), j'utilise l'invite SQL dans Management Studio: lors de l'écriture d'un INNER JOIN son InteliSense suggère des clauses ON basées à la fois sur les noms d'attributs communs et les clés étrangères et je le trouve très utile. Cependant, je n'ai pas vraiment envie de voir un nouveau type de jointure SQL (standard).

11
onedaywhen

SQL est venu en premier!

Les contraintes de clés étrangères et de clés étrangères sont venues plus tard et sont essentiellement une optimisation pour les applications de style "transaction".

Les bases de données relationnelles ont été conçues à l'origine comme une méthode d'application de requêtes complexes sur des ensembles de données d'une manière qui était mathématiquement prouvable en utilisant l'algèbre relationnelle. C'EST À DIRE. pour un ensemble de données et une requête donnés, il y a toujours une seule réponse correcte.

Les bases de données relationnelles ont parcouru un long chemin depuis lors, et leur utilisation principale comme couche de persistance pour les systèmes transactionnels n'était pas ce que CODD et. tout prévu.

Cependant, l'organisme de normalisation ANSI pour tous ses objectifs contradictoires et la politique des fournisseurs s'est toujours efforcé de préserver les propriétés "mathématiquement prouvables" de SQL.

Si vous autorisiez la base de données à déduire les propriétés de jointure à partir de données de clé étrangère "cachées", vous perdriez cette propriété (considérez l'ambiguïté si plusieurs jeux de clés étrangères étaient définis).

De plus, un programmeur lisant le SQL ne saurait pas nécessairement quelles clés étrangères sont actuellement définies pour les deux tables et devra examiner le schéma de la base de données pour déterminer ce que fait la requête.

9
James Anderson

Vous opérez peut-être sur une fausse hypothèse. Vous dites "autant que vous pouvez le découvrir" mais ne donnez aucune preuve empirique ou probante. Si le pk ou le fk sont le meilleur index pour une requête, il sera utilisé. Je ne sais pas pourquoi vous voyez cela, mais je suppose que les requêtes sont mal formulées.


Modifiez maintenant que la question a été entièrement réécrite: Le cas que vous décrivez ne concernerait qu'un très petit ensemble de requêtes. Et s'il y a 12 tables jointes? Et s'il n'y a pas de FK .... Même s'il y avait une jointure par défaut, je spécifierais toujours la jointure juste pour la lisibilité. (Je ne veux pas avoir à regarder les données et ensuite essayer de comprendre ce qui est joint)

Certains outils de requête effectuent en fait une jointure automatique pour vous, puis vous permettent de supprimer ou de modifier la jointure. Je pense que le générateur de requêtes de MS Access le fait.

Enfin, la norme ANSII stipule que la jointure doit être spécifiée. C'est une raison suffisante pour ne pas le permettre.

7
Morons

Bien que vous ayez défini une relation de clé étrangère, cela ne signifie pas que c'est ainsi que vous souhaitez joindre les tables dans toutes les requêtes. C'est la méthode la plus probable pour joindre les tables, mais il y a des cas où elle n'est pas correcte.

  • Vous pouvez utiliser un produit cartésien des deux tables ou une partie de celles-ci à des fins spécifiques.
  • Il peut y avoir d'autres champs sur lesquels vous pouvez vous joindre à une autre fin.
  • Si vous joignez trois tables ou plus, l'une des tables peut être liée à deux tables ou plus. Dans ce cas, généralement, une seule des relations FK possibles peut être appropriée dans la requête.
7
BillThor

Il existe de nombreuses raisons pour lesquelles la base de données ne peut pas le faire en toute sécurité, notamment le fait que l'ajout/la suppression de clés étrangères changera la signification des requêtes pré-écrites, y compris les requêtes dans le code source de l'application. La plupart des bases de données ne disposent pas non plus d'un bon ensemble de clés étrangères qui couvrent toutes les jointures possibles que vous voudrez probablement faire. Aussi, pour le meilleur ou pour le mieux, les clés étrangères sont souvent supprimées pour accélérer les systèmes et ne peuvent pas être utilisées sur des tables chargées dans le "mauvais" ordre à partir du fichier.

Cependant, il n'y a aucune raison pour laquelle une conception de requête outil ou l'éditeur de texte ne peut pas compléter automatiquement une jointure à l'aide de clés étrangères de la même manière qu'elles vous donnent intellisense sur le nom de la colonne. Vous pouvez modifier la requête si l'outil s'est trompé et enregistrer une requête complètement définie. Un tel outil pourrait également utilement utiliser la convention de nommer les colonnes de clés étrangères par le nom de la table "parent" et les colonnes de même nom dans la table parent/enfant, etc.

(Ma femme ne comprend toujours pas la différence entre Management Studio et Sql Server et parle de démarrer le serveur sql lorsqu'elle démarre Management Studio!)

3
Ian Ringrose

La jointure naturelle joint "automatiquement" les égalités des colonnes communes, mais vous ne devriez écrire cela que si c'est ce que vous voulez en fonction des significations du tableau et du résultat souhaité. Il n'y a pas "automatiquement" de savoir comment deux tables "devraient" être jointes ou de toute autre manière n'importe quelle table "devrait" apparaître dans une requête. Nous n'avons pas besoin de connaître les contraintes pour interroger. Leur présence signifie simplement que les entrées peuvent être limitées et, par conséquent, la sortie peut l'être aussi. Vous pouvez définir une sorte d'opérateur join_on_fk_to_pk qui joint "automatiquement" les contraintes déclarées; mais si vous voulez que la signification de la requête reste la même si seules les contraintes changent mais pas les significations de la table, vous devrez changer cette requête en pas utilisez les nouvelles contraintes déclarées. Le simple fait de donner la requête que vous voulez en utilisant join & conditions laisse déjà le même sens malgré tous les changements de contraintes .

Les contraintes (y compris les PK, FK, UNIQUE et CHECK) n'affectent pas la signification des tables. Bien sûr, si les significations du tableau changent, les contraintes peuvent changer. Mais si les contraintes changent, cela ne signifie pas que les requêtes doivent changer.

On n'a pas besoin de connaître les contraintes pour interroger. Connaître les contraintes signifie que nous pouvons utiliser d'autres expressions qui, sans le maintien de la contrainte, ne retourneraient pas la même réponse. Par exemple, en attendant via UNIQUE qu'une table a une ligne, nous pouvons donc l'utiliser comme scalaire. Ces requêtes peuvent se rompre si la contrainte a été supposée mais non déclarée. Mais déclarer une contrainte que la requête n'a pas supposée ne peut pas la casser.

Existe-t-il une règle générale pour construire une requête SQL à partir d'une description lisible par l'homme?

3
philipxy

La raison en est qu'il y a la LANGUE, puis les principes sous-jacents. Le langage est rare et manque de nombreuses fonctionnalités que vous attendez à voir dans un langage à usage général. Il s'agit simplement d'une fonctionnalité intéressante qui n'a pas été ajoutée à la langue et ne le sera probablement pas. Ce n'est pas une langue morte, donc il y a de l'espoir, mais je ne serais pas optimiste.

Comme d'autres l'ont souligné, certaines implémentations utilisent une extension où join (column) joint deux tables sur la base d'un nom de colonne commun, qui est quelque peu similaire. Mais ce n'est pas très répandu. Notez que cette extension est différente de la SELECT * FROM employee NATURAL JOIN department; syntaxe qui n'inclut pas un moyen de spécifier les colonnes à utiliser. Ni s'appuyer sur une relation entre les tables, ce qui les rend peu fiables (la syntaxe de jointure naturelle plus que l'extension).

Il n'y a pas d'obstacle fondamental à la "table de jointure interne sur PKFK" où PKFK est un mot clé signifiant "la relation de clé étrangère définie entre les deux tables", il pourrait y avoir des problèmes avec plusieurs fk vers la même table, mais cela pourrait simplement provoquer une erreur. La question est de savoir si les personnes qui conçoivent la langue considèrent que a) une bonne idée et b) mieux travailler que certains autres changements de langue ...

2
jmoreno

Si l'omission de la clause ON est supposée suivre les champs en fonction de l'intégrité référentielle, comment feriez-vous un produit cartésien?

Edit: en utilisant AUTO Les avantages de ceci sont un peu moins de frappe et vous n'avez pas besoin de savoir comment ils sont joints ou de vous souvenir d'une jointure compliquée. Si la relation change, elle est gérée automatiquement, mais cela arrive rarement sauf au début du développement.

Ce que vous devez faire maintenant est de décider si toutes vos jointures AUTO se maintiennent pendant un changement de relation pour correspondre à l'intention de votre instruction de sélection.

1
JeffO