PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Utiliser des jointures pour combiner des données de différentes tables dans PostgreSQL


Introduction

Le fractionnement des données associées dans des tables distinctes peut être bénéfique du point de vue de la cohérence, de la flexibilité et de certains types de performances. Cependant, vous avez toujours besoin d'un moyen raisonnable de réintégrer les enregistrements lorsque les informations pertinentes s'étendent sur plusieurs tables.

Dans les bases de données relationnelles, les jointures offrent un moyen de combiner les enregistrements dans deux tables ou plus en fonction de valeurs de champ communes. Différents types de jointures peuvent produire des résultats différents selon la façon dont les lignes sans correspondance doivent être traitées. Dans ce guide, nous aborderons les différents types de jointures proposés par PostgreSQL et comment vous pouvez les utiliser pour combiner des données de table provenant de plusieurs sources.



Que sont les jointures ?

En bref, joint sont un moyen d'afficher les données de plusieurs tables. Pour ce faire, ils assemblent des enregistrements de différentes sources en fonction des valeurs correspondantes dans certaines colonnes. Chaque ligne résultante consiste en un enregistrement de la première table combiné à une ligne de la seconde table, basée sur une ou plusieurs colonnes de chaque table ayant la même valeur.

La syntaxe de base d'une jointure ressemble à ceci :

SELECT    *FROM    <first_table><join_type> <second_table>    <join_condition>;

Dans une jointure, chaque ligne résultante est construite en incluant toutes les colonnes de la première table suivies de toutes les colonnes de la seconde table. Le SELECT partie de la requête peut être utilisée pour spécifier les colonnes exactes que vous souhaitez afficher.

Plusieurs lignes peuvent être construites à partir des tables d'origine si les valeurs des colonnes utilisées pour la comparaison ne sont pas uniques. Par exemple, imaginez que vous ayez une colonne comparée à partir de la première table qui a deux enregistrements avec une valeur de "rouge". Correspondant à ceci est une colonne de la deuxième table qui a trois lignes avec cette valeur. La jointure produira six lignes différentes pour cette valeur représentant les différentes combinaisons qui peuvent être obtenues.

Le type de jointure et les conditions de jointure déterminent la façon dont chaque ligne affichée est construite. Cela a un impact sur ce qui arrive aux lignes de chaque table qui font et ne font pas avoir une correspondance sur la condition de jointure.

Par souci de commodité, de nombreuses jointures correspondent à la clé primaire d'une table avec une clé étrangère associée sur la seconde table. Bien que les clés primaires et étrangères ne soient utilisées par le système de base de données que pour maintenir les garanties de cohérence, leur relation en fait souvent un bon candidat pour les conditions de jointure.



Différents types de jointures

Différents types de jointures sont disponibles, chacun produisant potentiellement des résultats différents. Comprendre comment chaque type est construit vous aidera à déterminer lequel est approprié pour différents scénarios.


Jointure interne

La jointure par défaut est appelée jointure interne . Dans PostgreSQL, cela peut être spécifié en utilisant soit INNER JOIN ou simplement JOIN .

Voici un exemple typique démontrant la syntaxe d'une jointure interne :

SELECT    *FROM    table_1[INNER] JOIN table_2    ON table_1.id = table_2.table_1_id;

Une jointure interne est le type de jointure le plus restrictif car elle n'affiche que les lignes créées en combinant les lignes de chaque table. Toutes les lignes des tables constitutives qui n'avaient pas d'équivalent correspondant dans l'autre table sont supprimées des résultats. Par exemple, si le premier tableau a une valeur "bleu" dans la colonne de comparaison et que le deuxième tableau n'a aucun enregistrement avec cette valeur, cette ligne sera supprimée de la sortie.

Si vous représentez les résultats sous forme de diagramme de Venn des tables de composants, une jointure interne vous permet de représenter la zone de chevauchement des deux cercles. Aucune des valeurs qui n'existaient que dans l'une des tables n'est affichée.



Joindre à gauche

Une jointure gauche est une jointure qui affiche tous les enregistrements trouvés dans une jointure interne, ainsi que tous les enregistrements sans correspondance lignes du premier tableau. Dans PostgreSQL, cela peut être spécifié comme un LEFT OUTER JOIN ou simplement une LEFT JOIN .

La syntaxe de base d'une jointure gauche suit ce modèle :

SELECT    *FROM    table_1LEFT JOIN table_2    ON table_1.id = table_2.table_1_id;

Une jointure gauche est construite en effectuant d'abord une jointure interne pour construire des lignes à partir de tous les enregistrements correspondants dans les deux tables. Ensuite, les enregistrements sans correspondance de la première table sont également inclus. Étant donné que chaque ligne d'une jointure inclut les colonnes des deux tables, les colonnes sans correspondance utilisent NULL comme valeur pour toutes les colonnes de la seconde table.

Si vous représentez les résultats sous la forme d'un diagramme de Venn des tables de composants, une jointure à gauche vous permet de représenter l'ensemble du cercle de gauche. Les parties du cercle de gauche représentées par l'intersection entre les deux cercles auront des données supplémentaires complétées par le tableau de droite.



Joindre à droite

Une jointure droite est une jointure qui affiche tous les enregistrements trouvés dans une jointure interne, ainsi que tous les enregistrements sans correspondance lignes du deuxième tableau. Dans PostgreSQL, cela peut être spécifié comme un RIGHT OUTER JOIN ou simplement comme RIGHT JOIN .

La syntaxe de base d'une jointure droite suit ce modèle :

SELECT    *FROM    table_1RIGHT JOIN table_2    ON table_1.id = table_2.table_1_id;

Une jointure droite est construite en effectuant d'abord une jointure interne pour construire des lignes à partir de tous les enregistrements correspondants dans les deux tables. Ensuite, les enregistrements sans correspondance de la deuxième table sont également inclus. Étant donné que chaque ligne d'une jointure inclut les colonnes des deux tables, les colonnes sans correspondance utilisent NULL comme valeur pour toutes les colonnes du premier tableau.

Si vous représentez les résultats sous la forme d'un diagramme de Venn des tables de composants, une jointure à droite vous permet de représenter l'intégralité du cercle droit. Les parties du cercle de droite représentées par l'intersection entre les deux cercles auront des données supplémentaires complétées par le tableau de gauche.



Jointure complète

Une jointure complète est une jointure qui affiche tous les enregistrements trouvés dans une jointure interne, ainsi que tous les enregistrements sans correspondance lignes des deux tables de composants. Dans PostgreSQL, cela peut être spécifié comme un FULL OUTER JOIN ou simplement comme FULL JOIN .

La syntaxe de base d'une jointure complète suit ce modèle :

SELECT    *FROM    table_1FULL JOIN table_2    ON table_1.id = table_2.table_1_id;

Une jointure complète est construite en effectuant d'abord une jointure interne pour construire des lignes à partir de tous les enregistrements correspondants dans les deux tables. Ensuite, les enregistrements sans correspondance des deux tables sont également inclus. Étant donné que chaque ligne d'une jointure inclut les colonnes des deux tables, les colonnes sans correspondance utilisent NULL comme valeur pour toutes les colonnes de l'autre table sans correspondance.

Si vous représentez les résultats sous la forme d'un diagramme de Venn des tables de composants, une jointure complète vous permet de représenter entièrement les deux cercles de composants. L'intersection des deux cercles aura des valeurs fournies par chacune des tables de composants. Les parties des cercles en dehors de la zone de chevauchement auront les valeurs de la table à laquelle elles appartiennent, en utilisant NULL pour remplir les colonnes présentes dans l'autre table.



Jointure croisée

Une jointure spéciale appelée CROSS JOIN est également disponible. Une jointure croisée n'utilise aucune comparaison pour déterminer si les lignes de chaque table correspondent les unes aux autres. Au lieu de cela, les résultats sont construits en ajoutant simplement chacune des lignes du premier tableau à chacune des lignes du second tableau.

Cela produit un produit cartésien des lignes de deux tables ou plus. En effet, ce style de jointure combine les lignes de chaque table sans condition. Ainsi, si chaque table a trois lignes, la table résultante aura neuf lignes contenant toutes les colonnes des deux tables.

Par exemple, si vous avez une table appelée t1 combiné avec une table appelée t2 , chacun avec des lignes r1 , r2 , et r3 , le résultat serait neuf lignes combinées comme suit :

t1.r1 + t2.r1t1.r1 + t2.r2t1.r1 + t2.r3t1.r2 + t2.r1t1.r2 + t2.r2t1.r2 + t2.r3t1.r3 + t2.r1t1.r3 + t2.r2t1.r3 + t2.r3


Auto-jointure

Une auto-jointure est une jointure qui combine les lignes d'une table avec elle-même. Il n'est peut-être pas immédiatement évident de savoir comment cela pourrait être utile, mais il a en fait de nombreuses applications courantes.

Souvent, les tables décrivent des entités qui peuvent remplir plusieurs rôles en relation les unes avec les autres. Par exemple, si vous avez une table de people , chaque ligne peut potentiellement contenir une mother colonne qui fait référence à d'autres people dans la table. Une auto-jointure vous permettrait d'assembler ces différentes lignes en joignant une deuxième instance de la table à la première où ces valeurs correspondent.

Étant donné que les jointures réflexives référencent deux fois la même table, des alias de table sont nécessaires pour lever l'ambiguïté des références. Dans l'exemple ci-dessus, par exemple, vous pouvez joindre les deux instances de people table utilisant les alias people AS children et people AS mothers . De cette façon, vous pouvez spécifier à quelle instance de la table vous vous référez lors de la définition des conditions de jointure.

Voici un autre exemple, représentant cette fois les relations entre les employés et les managers :

SELECT    *FROM    people AS employeeJOIN people AS manager    ON employee.manager_id = manager.id;



Conditions de jointure

Lors de la combinaison de tables, la condition de jointure détermine la manière dont les lignes seront mises en correspondance pour former les résultats composites. Le principe de base est de définir les colonnes de chaque table qui doivent correspondre pour que la jointure se produise sur cette ligne.


Le ON clause

La façon la plus standard de définir les conditions pour les jointures de table est avec le ON clause. Le ON La clause utilise un signe égal pour spécifier les colonnes exactes de chaque table qui seront comparées pour déterminer quand une jointure peut se produire. PostgreSQL utilise les colonnes fournies pour assembler les lignes de chaque table.

Le ON La clause est la plus détaillée, mais aussi la plus flexible des conditions de jointure disponibles. Il permet la spécificité, quelle que soit la standardisation des noms de colonne de chaque table combinée.

La syntaxe de base du ON clause ressemble à ceci :

SELECT    *FROM    table1JOIN    table2ON    table1.id = table2.ident;

Ici, les lignes de table1 et table2 sera joint à chaque fois que le id colonne de table1 correspond à l'ident colonne de table2 . Étant donné qu'une jointure interne est utilisée, les résultats n'afficheront que les lignes qui ont été jointes. Étant donné que la requête utilise le caractère générique * caractère, toutes les colonnes des deux tables seront affichées.

Cela signifie que l'id colonne de table1 et le ident colonne de table2 seront affichés, même s'ils ont exactement la même valeur en vertu de la satisfaction de la condition de jointure. Vous pouvez éviter cette duplication en appelant les colonnes exactes que vous souhaitez afficher dans le SELECT liste des colonnes.



Le USING clause

Le USING La clause est un raccourci pour spécifier les conditions d'un ON clause qui peut être utilisée lorsque les colonnes comparées portent le même nom dans les deux tables. Le USING La clause prend une liste, entre parenthèses, des noms de colonnes partagées qui doivent être comparées.

La syntaxe générale du USING clause utilise ce format :

SELECT    *FROM    table1JOIN    table2USING    (id, state);

Cette jointure combine table1 avec table2 lorsque deux colonnes que les deux tables partagent (id et state ) ont chacun des valeurs correspondantes.

Cette même jointure pourrait être exprimée de manière plus détaillée en utilisant ON comme ceci :

SELECT    *FROM    table1JOIN    table2ON    table1.id = table2.id AND table1.state = table2.state;

Alors que les deux jointures ci-dessus entraîneraient la construction des mêmes lignes avec les mêmes données présentes, elles seraient affichées légèrement différentes. Pendant que le ON La clause inclut toutes les colonnes des deux tables, la USING La clause supprime les colonnes en double. Ainsi, au lieu d'avoir deux id distincts colonnes et deux state séparés colonnes (une pour chaque table), les résultats n'auraient qu'une colonne de chacune des colonnes partagées, suivie de toutes les autres colonnes fournies par table1 et table2 .



Le NATURAL clause

Le NATURAL La clause est encore un autre raccourci qui peut encore réduire la verbosité de la USING clause. Un NATURAL join ne spécifie aucun colonnes à faire correspondre. Au lieu de cela, PostgreSQL joindra automatiquement les tables en fonction de toutes les colonnes qui ont des colonnes correspondantes dans chaque base de données.

La syntaxe générale du NATURAL la clause de jointure ressemble à ceci :

SELECT    *FROM    table1NATURAL JOIN    table2;

En supposant que table1 et table2 les deux ont des colonnes nommées id , state , et company , la requête ci-dessus serait équivalente à cette requête utilisant le ON clause :

SELECT    *FROM    table1JOIN    table2ON    table1.id = table2.id AND table1.state = table2.state AND table1.company = table2.company;

Et cette requête en utilisant le USING clause :

SELECT    *FROM    table1JOIN    table2USING    (id, state, company);

Comme le USING clause, le NATURAL La clause supprime les colonnes en double, de sorte qu'il n'y aurait qu'une seule instance de chacune des colonnes jointes dans les résultats.

Alors que le NATURAL clause peut réduire la verbosité de vos requêtes, il faut être prudent lors de son utilisation. Étant donné que les colonnes utilisées pour joindre les tables sont calculées automatiquement, si les colonnes des tables de composants changent, les résultats peuvent être très différents en raison des nouvelles conditions de jointure.




Conditions de jointure et WHERE clause

Les conditions de jointure partagent de nombreuses caractéristiques avec les comparaisons utilisées pour filtrer les lignes de données à l'aide de WHERE clauses. Les deux constructions définissent des expressions qui doivent avoir la valeur true pour que la ligne soit prise en compte. Pour cette raison, il n'est pas toujours intuitif quelle est la différence entre l'inclusion de comparaisons supplémentaires dans un WHERE construire plutôt que de les définir dans la clause de jointure elle-même.

Afin de comprendre les différences qui en résulteront, nous devons examiner l'ordre dans lequel PostgreSQL traite les différentes parties d'une requête. Dans ce cas, les prédicats de la condition de jointure sont traités en premier pour construire la table jointe virtuelle en mémoire. Après cette étape, les expressions dans le WHERE clause sont évaluées pour filtrer les lignes résultantes.

Par exemple, supposons que nous ayons deux tables appelées customer et order que nous devons nous unir. Nous voulons joindre les deux tables en faisant correspondre le customer.id colonne avec le order.customer_id colonne. De plus, nous sommes intéressés par les lignes de la order table qui a un product_id de 12345.

Compte tenu des exigences ci-dessus, nous avons deux conditions qui nous intéressent. Cependant, la façon dont nous exprimons ces conditions déterminera les résultats que nous recevrons.

Tout d'abord, utilisons les deux comme conditions de jointure pour un LEFT JOIN :

SELECT    customer.id AS customer_id,    customer.name,    order.id AS order_id,    order.product_idFROM    customerLEFT JOIN    orderON    customer.id = order.customer_id AND order.product_id = 12345;

Les résultats pourraient ressembler à ceci :

 customer_id |   name   | order_id | product_id ------------+----------+----------+------------        4380 | Acme Co  |      480 |      12345        4380 | Acme Co  |      182 |      12345         320 | Other Co |      680 |      12345        4380 | Acme Co  |          |         320 | Other Co |          |          20 | Early Co |          |        8033 | Big Co   |          |(7 rows)

PostgreSQL est arrivé à ce résultat en effectuant les opérations suivantes :

  1. Combinez toutes les lignes du customer tableau avec la order tableau où :
    • customer.id correspond à order.customer_id .
    • order.product_id correspond à 12345
  2. Parce que nous utilisons une jointure à gauche, incluez tout élément sans correspondance lignes du tableau de gauche (customer ), complétant les colonnes du tableau de droite (order ) avec NULL valeurs.
  3. Afficher uniquement les colonnes répertoriées dans le SELECT spécification de colonne.

Le résultat est que toutes nos lignes jointes correspondent aux deux conditions que nous recherchons. Cependant, la jointure gauche oblige PostgreSQL à inclure également toutes les lignes de la première table qui n'ont pas satisfait la condition de jointure. Cela se traduit par des lignes "restantes" qui ne semblent pas suivre l'intention apparente de la requête.

Si nous déplaçons la deuxième requête (order.product_id =12345) à un WHERE clause, au lieu de l'inclure comme condition de jointure, nous obtenons des résultats différents :

SELECT    customer.id AS customer_id,    customer.name,    order.id AS order_id,    order.product_idFROM    customerLEFT JOIN    orderON    customer.id = order.customer_idWHERE    order.product_id = 12345;

Cette fois, seules trois lignes sont affichées :

 customer_id |   name   | order_id | product_id ------------+----------+----------+------------        4380 | Acme Co  |      480 |      12345        4380 | Acme Co  |      182 |      12345         320 | Other Co |      680 |      12345(3 rows)

L'ordre dans lequel les comparaisons sont exécutées est la raison de ces différences. Cette fois, PostgreSQL traite la requête comme ceci :

  1. Combinez toutes les lignes du customer tableau avec la order table où customer.id correspond à order.customer_id .
  2. Parce que nous utilisons une jointure à gauche, incluez tout élément sans correspondance lignes du tableau de gauche (customer ), complétant les colonnes du tableau de droite (order ) avec NULL valeurs.
  3. Évaluer le WHERE clause pour supprimer toutes les lignes qui n'ont pas 12345 comme valeur pour order.product_id colonne.
  4. Afficher uniquement les colonnes répertoriées dans le SELECT spécification de colonne.

Cette fois, même si nous utilisons une jointure gauche, le WHERE la clause tronque les résultats en filtrant toutes les lignes sans le bon product_id . Parce que toutes les lignes sans correspondance auraient product_id défini sur NULL , cela supprime toutes les lignes sans correspondance qui ont été remplies par la jointure gauche. Il supprime également toutes les lignes correspondant à la condition de jointure qui n'ont pas réussi cette deuxième série de vérifications.

Comprendre le processus de base utilisé par PostgreSQL pour exécuter vos requêtes peut vous aider à éviter certaines erreurs faciles à commettre mais difficiles à déboguer lorsque vous travaillez avec vos données.



Conclusion

Dans ce guide, nous avons expliqué comment les jointures permettent aux bases de données relationnelles de combiner les données de différentes tables pour fournir des réponses plus utiles. Nous avons parlé des différentes jointures prises en charge par PostgreSQL, de la manière dont chaque type assemble ses résultats et de ce à quoi s'attendre lors de l'utilisation de types de jointures spécifiques. Ensuite, nous avons examiné différentes manières de définir les conditions de jointure et examiné comment l'interaction entre les jointures et le WHERE clause peut entraîner des surprises.

Les jointures sont une partie essentielle de ce qui rend les bases de données relationnelles suffisamment puissantes et flexibles pour gérer autant de types de requêtes différents. L'organisation des données à l'aide de limites logiques tout en étant capable de recombiner les données de manière novatrice au cas par cas confère aux bases de données relationnelles comme PostgreSQL une polyvalence incroyable. Apprendre à effectuer cet assemblage entre les tables vous permettra de créer des requêtes plus complexes et de vous appuyer sur la base de données pour créer des images complètes de vos données.