web-dev-qa-db-fra.com

SQL JOIN et différents types de JOIN

Qu'est-ce qu'un SQL JOIN et quels sont les différents types?

232
M-D

Qu'est-ce que SQL JOIN?

SQL JOIN est une méthode permettant d'extraire des données de deux ou plusieurs tables de base de données.

Quels sont les différents SQL JOINs?

Il y a un total de cinq JOINs. Elles sont :

  1. JOIN or INNER JOIN
  2. OUTER JOIN

     2.1 LEFT OUTER JOIN or LEFT JOIN
     2.2 RIGHT OUTER JOIN or RIGHT JOIN
     2.3 FULL OUTER JOIN or FULL JOIN

  3. NATURAL JOIN
  4. CROSS JOIN
  5. SELF JOIN

1. JOIN ou INNER JOIN:

Dans ce type de JOIN, nous obtenons tous les enregistrements correspondant à la condition dans les deux tables et les enregistrements des deux tables qui ne correspondent pas ne sont pas signalés.

En d'autres termes, INNER JOIN est basé sur le seul fait que: SEULES les entrées correspondantes dans LES DEUX tables DOIVENT être répertoriées.

Notez qu'un JOIN sans autre mot-clé JOIN (comme INNER, OUTER, LEFT, etc.) est un INNER JOIN. En d'autres termes, JOIN est un sucre syntaxique pour INNER JOIN (voir: Différence entre JOIN et INNER JOIN ).

2. JOINT EXTÉRIEUR:

OUTER JOIN récupère

Soit les lignes correspondantes d'une table et toutes les lignes de l'autre table, soit toutes les lignes de toutes les tables (peu importe qu'il y ait ou non une correspondance).

Il existe trois types de jointure externe:

2.1 LEFT OUTER JOIN ou LEFT JOIN

Cette jointure renvoie toutes les lignes de la table de gauche en association avec les lignes correspondantes de la table de droite. Si aucune colonne ne correspond dans la table de droite, les valeurs NULL sont renvoyées.

2.2 RIGHT OUTER JOIN ou RIGHT JOIN

Cette JOIN renvoie toutes les lignes de la table de droite en conjonction avec les lignes correspondantes de la table de gauche. S'il n'y a pas de colonnes correspondant dans la table de gauche, les valeurs NULL sont renvoyées.

2.3 FULL OUTER JOIN ou FULL JOIN

Cette JOIN combine LEFT OUTER JOIN et RIGHT OUTER JOIN. Il renvoie des lignes de l'une ou l'autre table lorsque les conditions sont remplies et renvoie la valeur NULL lorsqu'il n'y a pas de correspondance.

En d'autres termes, OUTER JOIN est basé sur le fait que: SEULEMENT les entrées correspondantes dans UNE DES tables (DROITE ou GAUCHE) ou DES DEUX tables (FULL) DEVRAIENT être répertoriées.

Note that `OUTER JOIN` is a loosened form of `INNER JOIN`.

3. JOINDRE NATUREL:

Il est basé sur les deux conditions:

  1. la JOIN est faite sur toutes les colonnes du même nom pour égalité.
  2. Supprime les colonnes en double du résultat.

Cela semble être de nature plus théorique et, par conséquent, la plupart des SGBD ne s’ennuient même pas.

4. CROSS JOIN:

C'est le produit cartésien des deux tables impliquées. Le résultat d'un CROSS JOIN n'aura aucun sens dans la plupart des situations. De plus, nous n’aurons pas besoin de cela du tout (ou du moins, pour être précis).

5. SELF JOIN:

Ce n'est pas une forme différente de JOIN, mais plutôt une JOIN (INNER, OUTER, etc.) d'une table à elle-même.

JOINs basés sur des opérateurs

Selon l'opérateur utilisé pour une clause JOIN, il peut exister deux types de JOINs. Elles sont

  1. Equi JOIN
  2. Theta JOIN

1. Equi JOIN:

Quel que soit le type JOIN (INNER, OUTER, etc), si nous utilisons UNIQUEMENT l'opérateur d'égalité (=), nous dirons que la JOIN est un EQUI JOIN.

2. Theta JOIN:

Ceci est identique à EQUI JOIN mais il autorise tous les autres opérateurs tels que>, <,> = etc.

Beaucoup considèrent que EQUI JOIN et Theta JOIN sont similaires à INNER, OUTER etc JOINs. Mais je crois fermement que c'est une erreur et que les idées sont vagues. Parce que INNER JOIN, OUTER JOIN etc sont tous liés aux tables et à leurs données alors que EQUI JOIN et THETA JOIN ne sont connectés qu'aux opérateurs que nous utilisons dans le premier.

Encore une fois, nombreux sont ceux qui considèrent NATURAL JOIN comme une sorte de "particulier" EQUI JOIN. En fait, c’est vrai, à cause de la première condition mentionnée pour NATURAL JOIN. Cependant, il n'est pas nécessaire de limiter cela simplement à NATURAL JOINs. INNER JOINs, OUTER JOINs etc. pourrait également être un EQUI JOIN.

239
M-D

Une illustration de W3schools :


INNER JOIN - Only records which match the condition in both tables


LEFT JOIN - All records from table 1 in conjunction with records which match the condition in table 2


RIGHT JOIN - All records from table 2 in conjunction with records from table 1 which match the condition


FULL OUTER JOIN - Combination of both Left and Right Outer joins matching ON clause but preserving both tables


321
Anup

Définition:


JOINS permet d’interroger les données combinées de plusieurs tables simultanément.

Types de JOINS:


Concernant les SGBDR, il existe 5 types de jointures:

  • Equi-Join: Combine les enregistrements courants de deux tables en fonction de la condition d'égalité. Techniquement, la jointure est faite en utilisant l’opérateur d’égalité (=) pour comparer les valeurs de la clé primaire d’une table et les valeurs de la clé étrangère d’une autre table; l’ensemble de résultats comprend donc les enregistrements communs (correspondants) des deux tables. Pour la mise en œuvre, voir INNER-JOIN.

  • Natural-Join: Il s'agit d'une version améliorée d'Equi-Join, dans laquelle l'opération SELECT omet la colonne en double. Pour la mise en œuvre, voir INNER-JOIN

  • Non-Equi-Join: Il s'agit de l'inverse de Equi-join où la condition de jointure est utilisée à des fins autres que l'opérateur égal (=), par exemple,! =, <= ,> =,>, <ou BETWEEN, etc. Pour la mise en oeuvre, voir INNER-JOIN.

  • Auto-jointure: : comportement personnalisé de jointure dans lequel une table est combinée à elle-même; Cela est généralement nécessaire pour interroger des tables auto-référencées (ou une entité de relation unaire). Pour la mise en œuvre, voir INNER-JOINs.

  • Produit cartésien: Il combine tous les enregistrements des deux tables sans aucune condition. Techniquement, il retourne le jeu de résultats d'une requête sans WHERE-Clause.

Selon les préoccupations et les progrès de SQL, il existe 3 types de jointures et toutes les jointures de SGBDR peuvent être réalisées à l'aide de ces types de jointures.

  1. INNER-JOIN: Il fusionne (ou combine) les lignes correspondantes de deux tables. La mise en correspondance est effectuée sur la base de colonnes communes de tables et de leur opération de comparaison. Si condition basée sur l'égalité alors: EQUI-JOIN exécuté, sinon Non-EQUI-Join.

  2. OUTER-JOIN: Il fusionne (ou combine) les lignes correspondantes de deux tables et des lignes sans correspondance avec des valeurs NULL. Toutefois, vous pouvez personnaliser la sélection de lignes non appariées, par exemple en sélectionnant une ligne non appariée dans la première table ou dans la seconde table par sous-types: LEFT OUTER JOIN et RIGHT OUTER JOIN.

    2.1. LEFT Outer JOIN (a.k.a, LEFT-JOIN): renvoie les lignes correspondantes de deux tables et non identiques de la table LEFT (c'est-à-dire la première table).

    2.2. RIGHT JOIN (a.k.a, RIGHT-JOIN): retourne les lignes correspondantes de deux tables et non appariées de la table RIGHT.

    2.3. FULL OUTER JOIN (a.k.a OUTER JOIN): renvoie les éléments correspondants et non identiques des deux tables.

  3. CROSS-JOIN: Cette jointure ne fusionne/combine pas mais produit un produit cartésien.

enter image description here Remarque: Self-JOIN peut être obtenu par INNER-JOIN, OUTER-JOIN et CROSS-JOIN en fonction des besoins, mais la table doit être jointe à elle-même.

Pour plus d'informations:

Exemples:

1.1: INNER-JOIN: Implémentation d'Equi-join

SELECT  *
FROM Table1 A 
 INNER JOIN Table2 B ON A.<Primary-Key> =B.<Foreign-Key>;

1.2: INNER-JOIN: implémentation de Natural-JOIN

Select A.*, B.Col1, B.Col2          --But no B.ForeignKeyColumn in Select
 FROM Table1 A
 INNER JOIN Table2 B On A.Pk = B.Fk;

1.3: Implémentation INNER-JOIN avec une implémentation NON-Equi-join

Select *
 FROM Table1 A INNER JOIN Table2 B On A.Pk <= B.Fk;

1.4: INNER-JOIN avec SELF-JOIN

Select *
 FROM Table1 A1 INNER JOIN Table1 A2 On A1.Pk = A2.Fk;

2.1: OUTER JOIN (jointure externe complète)

Select *
 FROM Table1 A FULL OUTER JOIN Table2 B On A.Pk = B.Fk;

2.2: LEFT JOIN

Select *
 FROM Table1 A LEFT OUTER JOIN Table2 B On A.Pk = B.Fk;

2.3: DROITE JOIN

Select *
 FROM Table1 A RIGHT OUTER JOIN Table2 B On A.Pk = B.Fk;

3.1: CROSS JOIN

Select *
 FROM TableA CROSS JOIN TableB;

3.2: CROSS JOIN-Self JOIN

Select *
 FROM Table1 A1 CROSS JOIN Table1 A2;

//OU//

Select *
 FROM Table1 A1,Table1 A2;
65

Fait intéressant, la plupart des autres réponses souffrent de ces deux problèmes:

J'ai récemment écrit un article sur le sujet: n guide probablement incomplet et complet sur les nombreuses façons de joindre des tables en SQL , que je vais résumer ici.

D'abord et avant tout: les JOIN sont des produits cartésiens

C'est pourquoi les diagrammes de Venn les expliquent de manière si inexacte, car une jointure crée un produit cartésien entre les deux tables jointes. Wikipedia l'illustre bien:

enter image description here

La syntaxe SQL des produits cartésiens est CROSS JOIN. Par exemple:

SELECT *

-- This just generates all the days in January 2017
FROM generate_series(
  '2017-01-01'::TIMESTAMP,
  '2017-01-01'::TIMESTAMP + INTERVAL '1 month -1 day',
  INTERVAL '1 day'
) AS days(day)

-- Here, we're combining all days with all departments
CROSS JOIN departments

Qui combine toutes les lignes d'une table avec toutes les lignes de l'autre table:

La source:

+--------+   +------------+
| day    |   | department |
+--------+   +------------+
| Jan 01 |   | Dept 1     |
| Jan 02 |   | Dept 2     |
| ...    |   | Dept 3     |
| Jan 30 |   +------------+
| Jan 31 |
+--------+

Résultat:

+--------+------------+
| day    | department |
+--------+------------+
| Jan 01 | Dept 1     |
| Jan 01 | Dept 2     |
| Jan 01 | Dept 3     |
| Jan 02 | Dept 1     |
| Jan 02 | Dept 2     |
| Jan 02 | Dept 3     |
| ...    | ...        |
| Jan 31 | Dept 1     |
| Jan 31 | Dept 2     |
| Jan 31 | Dept 3     |
+--------+------------+

Si nous écrivons simplement une liste de tables séparées par des virgules, nous obtiendrons le même résultat:

-- CROSS JOINing two tables:
SELECT * FROM table1, table2

INNER JOIN (Theta-JOIN)

Un INNER JOIN est simplement un CROSS JOIN filtré où le prédicat de filtre est appelé Theta en algèbre relationnelle.

Par exemple:

SELECT *

-- Same as before
FROM generate_series(
  '2017-01-01'::TIMESTAMP,
  '2017-01-01'::TIMESTAMP + INTERVAL '1 month -1 day',
  INTERVAL '1 day'
) AS days(day)

-- Now, exclude all days/departments combinations for
-- days before the department was created
JOIN departments AS d ON day >= d.created_at

Notez que le mot clé INNER est facultatif (sauf dans MS Access).

( regardez l'article pour des exemples de résultats )

EQUI JOIN

Equi JOIN est un type spécial de Theta-JOIN, que nous utilisons le plus souvent. Le prédicat joint la clé primaire d'une table à la clé étrangère d'une autre table. Si nous utilisons le base de données Sakila à titre d'illustration, nous pouvons écrire:

SELECT *
FROM actor AS a
JOIN film_actor AS fa ON a.actor_id = fa.actor_id
JOIN film AS f ON f.film_id = fa.film_id

Cela combine tous les acteurs avec leurs films.

Ou aussi, sur certaines bases de données:

SELECT *
FROM actor
JOIN film_actor USING (actor_id)
JOIN film USING (film_id)

La syntaxe USING() permet de spécifier une colonne devant figurer de part et d'autre des tables d'une opération JOIN et crée un prédicat d'égalité sur ces deux colonnes.

JOINDRE NATUREL

D'autres réponses ont répertorié ce "type JOIN" séparément, mais cela n'a aucun sens. C'est juste une forme de sucre de syntaxe pour equi JOIN, qui est un cas particulier de Theta-JOIN ou INNER JOIN. NATURAL JOIN collecte simplement toutes les colonnes communes aux deux tables à joindre et joint USING() ces colonnes. Ce qui n’est guère utile, à cause de correspondances accidentelles (comme LAST_UPDATE colonnes dans base de données Sakila ).

Voici la syntaxe:

SELECT *
FROM actor
NATURAL JOIN film_actor
NATURAL JOIN film

JOINT EXTÉRIEUR

Maintenant, OUTER JOIN est un peu différent de INNER JOIN car il crée une UNION de plusieurs produits cartésiens. Nous pouvons écrire:

-- Convenient syntax:
SELECT *
FROM a LEFT JOIN b ON <predicate>

-- Cumbersome, equivalent syntax:
SELECT a.*, b.*
FROM a JOIN b ON <predicate>
UNION ALL
SELECT a.*, NULL, NULL, ..., NULL
FROM a
WHERE NOT EXISTS (
  SELECT * FROM b WHERE <predicate>
)

Personne ne veut écrire ce dernier, donc nous écrivons OUTER JOIN (qui est généralement mieux optimisé par les bases de données).

Comme INNER, le mot clé OUTER est facultatif, ici.

OUTER JOIN est disponible en trois versions:

  • LEFT [ OUTER ] JOIN: La table de gauche de l'expression JOIN est ajoutée à l'union comme indiqué ci-dessus.
  • RIGHT [ OUTER ] JOIN: Le tableau de droite de l'expression JOIN est ajouté à l'union comme indiqué ci-dessus.
  • FULL [ OUTER ] JOIN: les deux tables de l'expression JOIN sont ajoutées à l'union, comme indiqué ci-dessus.

Tous ces éléments peuvent être combinés avec le mot clé USING() ou avec NATURAL ( j'ai eu récemment un cas d'utilisation réel pour un NATURAL FULL JOIN) )

Syntaxes alternatives

Il existe des syntaxes historiques et obsolètes dans Oracle et SQL Server, qui prenaient déjà en charge OUTER JOIN avant que le standard SQL ne dispose d'une syntaxe:

-- Oracle
SELECT *
FROM actor a, film_actor fa, film f
WHERE a.actor_id = fa.actor_id(+)
AND fa.film_id = f.film_id(+)

-- SQL Server
SELECT *
FROM actor a, film_actor fa, film f
WHERE a.actor_id *= fa.actor_id
AND fa.film_id *= f.film_id

Cela dit, n'utilisez pas cette syntaxe. Je viens d’énumérer ceci ici afin que vous puissiez le reconnaître à partir d’anciens articles de blog/code hérité.

Partitionné OUTER JOIN

Peu de gens le savent, mais le standard SQL spécifie OUTER JOIN partitionné (et Oracle le met en œuvre). Vous pouvez écrire des choses comme ceci:

WITH

  -- Using CONNECT BY to generate all dates in January
  days(day) AS (
    SELECT DATE '2017-01-01' + LEVEL - 1
    FROM dual
    CONNECT BY LEVEL <= 31
  ),

  -- Our departments
  departments(department, created_at) AS (
    SELECT 'Dept 1', DATE '2017-01-10' FROM dual UNION ALL
    SELECT 'Dept 2', DATE '2017-01-11' FROM dual UNION ALL
    SELECT 'Dept 3', DATE '2017-01-12' FROM dual UNION ALL
    SELECT 'Dept 4', DATE '2017-04-01' FROM dual UNION ALL
    SELECT 'Dept 5', DATE '2017-04-02' FROM dual
  )
SELECT *
FROM days 
LEFT JOIN departments 
  PARTITION BY (department) -- This is where the magic happens
  ON day >= created_at

Parties du résultat:

+--------+------------+------------+
| day    | department | created_at |
+--------+------------+------------+
| Jan 01 | Dept 1     |            | -- Didn't match, but still get row
| Jan 02 | Dept 1     |            | -- Didn't match, but still get row
| ...    | Dept 1     |            | -- Didn't match, but still get row
| Jan 09 | Dept 1     |            | -- Didn't match, but still get row
| Jan 10 | Dept 1     | Jan 10     | -- Matches, so get join result
| Jan 11 | Dept 1     | Jan 10     | -- Matches, so get join result
| Jan 12 | Dept 1     | Jan 10     | -- Matches, so get join result
| ...    | Dept 1     | Jan 10     | -- Matches, so get join result
| Jan 31 | Dept 1     | Jan 10     | -- Matches, so get join result

Le point ici est que toutes les lignes du côté partitionné de la jointure finiront dans le résultat, que la JOIN corresponde à quoi que ce soit de "l'autre côté du JOIN". Longue histoire: Ceci est pour remplir des données éparses dans les rapports. Très utile!

SEMI JOIN

Sérieusement? Aucune autre réponse a ceci? Bien sûr que non, car il n’a malheureusement pas de syntaxe native en SQL (tout comme ANTI JOIN ci-dessous). Mais nous pouvons utiliser IN() et EXISTS(), par exemple. pour trouver tous les acteurs qui ont joué dans des films:

SELECT *
FROM actor a
WHERE EXISTS (
  SELECT * FROM film_actor fa
  WHERE a.actor_id = fa.actor_id
)

Le prédicat WHERE a.actor_id = fa.actor_id joue le rôle de prédicat semi-jointure. Si vous ne le croyez pas, consultez les plans d’exécution, par exemple dans Oracle. Vous verrez que la base de données exécute une opération SEMI JOIN, et non le prédicat EXISTS().

enter image description here

ANTI JOIN

C'est juste l'opposé de SEMI JOIN ( faites attention de ne pas utiliser NOT IN bien que) , car il y a une mise en garde importante)

Voici tous les acteurs sans films:

SELECT *
FROM actor a
WHERE NOT EXISTS (
  SELECT * FROM film_actor fa
  WHERE a.actor_id = fa.actor_id
)

Certaines personnes (en particulier les personnes de MySQL) écrivent également ANTI JOIN comme ceci:

SELECT *
FROM actor a
LEFT JOIN film_actor fa
USING (actor_id)
WHERE film_id IS NULL

Je pense que la raison historique est la performance.

JOINDRE LATÉRAL

OMG, celui-ci est trop cool. Je suis le seul à en parler? Voici une requête intéressante:

SELECT a.first_name, a.last_name, f.*
FROM actor AS a
LEFT OUTER JOIN LATERAL (
  SELECT f.title, SUM(amount) AS revenue
  FROM film AS f
  JOIN film_actor AS fa USING (film_id)
  JOIN inventory AS i USING (film_id)
  JOIN rental AS r USING (inventory_id)
  JOIN payment AS p USING (rental_id)
  WHERE fa.actor_id = a.actor_id -- JOIN predicate with the outer query!
  GROUP BY f.film_id
  ORDER BY revenue DESC
  LIMIT 5
) AS f
ON true

Il trouvera le TOP 5 des films générant des revenus par acteur. Chaque fois que vous avez besoin d'une requête TOP-N-per-quelque chose, LATERAL JOIN sera votre ami. Si vous êtes un utilisateur de SQL Server, vous connaissez ce type JOIN sous le nom APPLY

SELECT a.first_name, a.last_name, f.*
FROM actor AS a
OUTER APPLY (
  SELECT f.title, SUM(amount) AS revenue
  FROM film AS f
  JOIN film_actor AS fa ON f.film_id = fa.film_id
  JOIN inventory AS i ON f.film_id = i.film_id
  JOIN rental AS r ON i.inventory_id = r.inventory_id
  JOIN payment AS p ON r.rental_id = p.rental_id
  WHERE fa.actor_id = a.actor_id -- JOIN predicate with the outer query!
  GROUP BY f.film_id
  ORDER BY revenue DESC
  LIMIT 5
) AS f

OK, c'est peut-être une tricherie, car une expression LATERAL JOIN ou APPLY est en réalité une "sous-requête corrélée" qui produit plusieurs lignes. Mais si nous autorisons les "sous-requêtes corrélées", nous pouvons aussi parler de ...

MULTISET

Ceci est seulement réellement implémenté par Oracle et Informix (à ma connaissance), mais il peut être émulé dans PostgreSQL en utilisant des tableaux et/ou XML et dans SQL Server en utilisant XML.

MULTISET génère une sous-requête corrélée et imbrique le jeu de lignes résultant dans la requête externe. La requête ci-dessous sélectionne tous les acteurs et chaque acteur collecte ses films dans une collection imbriquée:

SELECT a.*, MULTISET (
  SELECT f.*
  FROM film AS f
  JOIN film_actor AS fa USING (film_id)
  WHERE a.actor_id = fa.actor_id
) AS films
FROM actor

Comme vous l'avez vu, il existe plus de types de JOIN que les "ennuyeux" INNER, OUTER et CROSS JOIN habituellement mentionnés. Plus de détails dans mon article . Et s'il vous plaît, arrêtez d'utiliser des diagrammes de Venn pour les illustrer.

37
Lukas Eder

J'ai créé une illustration qui explique mieux que les mots, à mon avis: SQL Join table of explanation

9
Gisway