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 :
- Combinez toutes les lignes du
customer
tableau avec laorder
tableau où :customer.id
correspond àorder.customer_id
.order.product_id
correspond à 12345
- 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
) avecNULL
valeurs. - 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 :
- Combinez toutes les lignes du
customer
tableau avec laorder
table oùcustomer.id
correspond àorder.customer_id
. - 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
) avecNULL
valeurs. - Évaluer le
WHERE
clause pour supprimer toutes les lignes qui n'ont pas 12345 comme valeur pourorder.product_id
colonne. - 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.