Comment faire une jointure complète en MySQL?

je veux faire une jointure externe complète dans MySQL. Est-ce possible? Est-ce Qu'une jointure externe complète est supportée par MySQL?

497
demandé sur Steve Chambers 2011-01-25 20:34:18

15 réponses

vous n'avez pas de jointures complètes sur MySQL, mais vous pouvez sûr les émuler .

pour un échantillon de code transcrit à partir de this SO question you have:

avec deux tableaux t1, t2:

SELECT * FROM t1
LEFT JOIN t2 ON t1.id = t2.id
UNION
SELECT * FROM t1
RIGHT JOIN t2 ON t1.id = t2.id

la requête ci-dessus fonctionne pour les cas spéciaux où une opération de jointure extérieure complète ne produirait pas de lignes en double. La requête ci-dessus dépend du UNION définir l'opérateur pour supprimer les lignes dupliquées introduites par le motif de requête. Nous pouvons éviter d'introduire des lignes dupliquées en utilisant un anti-jointure pattern pour la deuxième requête, puis utiliser un opérateur UNION ALL set pour combiner les deux ensembles. Dans le cas plus général, où une jointure extérieure complète retournerait les lignes dupliquées, nous pouvons faire ceci:

  SELECT * FROM t1
  LEFT JOIN t2 ON t1.id = t2.id
  UNION ALL
  SELECT * FROM t1
  RIGHT JOIN t2 ON t1.id = t2.id
  WHERE t1.id IS NULL
495
répondu Pablo Santa Cruz 2017-11-06 15:07:27

la réponse que Pablo Santa Cruz a donné est correcte; cependant, au cas où quelqu'un est tombé sur cette page et veut plus de clarification, voici une ventilation détaillée.

Exemples De Tables

supposons que nous ayons les tableaux suivants:

-- t1
id  name
1   Tim
2   Marta

-- t2
id  name
1   Tim
3   Katarina

Jointures Internes

une jonction intérieure, comme ceci:

SELECT *
FROM `t1`
INNER JOIN `t2` ON `t1`.`id` = `t2`.`id`;

ne nous obtiendrait que des enregistrements apparaissent dans les deux tableaux, comme ceci:

1 Tim  1 Tim

les jonctions intérieures n'ont pas de direction (comme gauche ou droite) parce qu'elles sont explicitement bidirectionnelles - nous avons besoin d'une correspondance des deux côtés.

Joints Extérieurs

les jointures Externes, d'autre part, sont pour rechercher des enregistrements qui n'ont pas de correspondance dans l'autre table. En tant que tel, vous devez spécifier quel côté de la jointure est autorisé à avoir un manquant dossier.

LEFT JOIN et RIGHT JOIN sont un raccourci pour LEFT OUTER JOIN et RIGHT OUTER JOIN ; je vais l'utiliser leurs noms, prénoms ci-dessous afin de renforcer le concept de jointures externes vs jointures internes.

Joint Extérieur Gauche

une jointure extérieure gauche, comme ceci:

SELECT *
FROM `t1`
LEFT OUTER JOIN `t2` ON `t1`.`id` = `t2`.`id`;

...nous obtiendrions tous les enregistrements de la table de gauche, qu'ils aient ou non une correspondance dans la table de droite, comme ceci:

1 Tim   1    Tim
2 Marta NULL NULL

Droit Extérieur Jointure

une jointure extérieure droite, comme ceci:

SELECT *
FROM `t1`
RIGHT OUTER JOIN `t2` ON `t1`.`id` = `t2`.`id`;

...nous obtiendrions tous les enregistrements de la table de droite, qu'ils aient ou non une correspondance dans la table de gauche, comme ceci:

1    Tim   1  Tim
NULL NULL  3  Katarina

Full Outer Join

Une jointure externe complète serait de nous donner tous les enregistrements des deux tables, qu'ils aient ou non une correspondance dans l'autre table, avec des Nuls des deux côtés où il n'y a pas de match. Le résultat ressemblerait à ceci:

1    Tim   1    Tim
2    Marta NULL NULL
NULL NULL  3    Katarina

cependant, comme Pablo Santa Cruz l'a souligné, MySQL ne soutient pas cela. Nous pouvons l'émuler en faisant L'UNION d'une gauche et d'une droite, comme ceci:

SELECT *
FROM `t1`
LEFT OUTER JOIN `t2` ON `t1`.`id` = `t2`.`id`

UNION

SELECT *
FROM `t1`
RIGHT OUTER JOIN `t2` ON `t1`.`id` = `t2`.`id`;

vous pouvez penser à un UNION comme signifiant "exécuter ces deux requêtes, puis empiler les résultats les uns sur les autres"; certaines des lignes viendront de la première requête et certains à partir de la deuxième.

il est à noter qu'un UNION dans MySQL éliminera les doublons exacts: Tim apparaîtrait dans les deux requêtes ici, mais le résultat du UNION ne le répertorie qu'une seule fois. Mon collègue gourou de base de données pense que ce comportement ne devrait pas être fiable. Donc, pour être plus explicite à ce sujet, nous pourrions ajouter une clause WHERE à la seconde requête:

SELECT *
FROM `t1`
LEFT OUTER JOIN `t2` ON `t1`.`id` = `t2`.`id`

UNION

SELECT *
FROM `t1`
RIGHT OUTER JOIN `t2` ON `t1`.`id` = `t2`.`id`
WHERE `t1`.`id` IS NULL;

d'autre part, si vous voulu pour voir les doublons pour une raison quelconque, vous pouvez utiliser UNION ALL .

302
répondu Nathan Long 2017-05-23 11:55:11

L'utilisation d'une requête union supprimera les doublons, et ceci est différent du comportement de full outer join qui ne supprime jamais aucun doublon:

[Table: t1]                            [Table: t2]
value                                  value
-------                                -------
1                                      1
2                                      2
4                                      2
4                                      5

C'est le résultat attendu de full outer join :

value | value
------+-------
1     | 1
2     | 2
2     | 2
Null  | 5
4     | Null
4     | Null

résultat de l'utilisation de left et right Join avec union :

value | value
------+-------
Null  | 5 
1     | 1
2     | 2
4     | Null

[SQL Fiddle]

ma requête suggérée est:

select 
    t1.value, t2.value
from t1 
left outer join t2  
  on t1.value = t2.value
union all      -- Using `union all` instead of `union`
select 
    t1.value, t2.value
from t2 
left outer join t1 
  on t1.value = t2.value
where 
    t1.value IS NULL 

résultat de la requête ci-dessus qui est le même que le résultat attendu:

value | value
------+-------
1     | 1
2     | 2
2     | 2
4     | NULL
4     | NULL
NULL  | 5

[SQL Fiddle]


@Steve Chambers : [des commentaires, avec beaucoup de remerciements!]

Note:: cela peut être la meilleure solution, à la fois pour l'efficacité et pour produire les mêmes résultats qu'un FULL OUTER JOIN . ce billet de blog l'explique aussi bien - pour citer la méthode 2: " cela gère les lignes dupliquées correctement et n'inclut rien qu'il ne devrait pas. Il est nécessaire d'utiliser UNION ALL au lieu de UNION , ce qui éliminerait les doublons que je veux garder. Cela peut être beaucoup plus efficace sur de grands ensembles de résultats, depuis il n'y a pas besoin de trier et supprimer les doublons."


j'ai décidé d'ajouter une autre solution qui vient de full outer join visualisation et les mathématiques, il n'est pas préférable que ci-dessus, mais plus lisible:

assemblage complet extérieur signifie (t1 ∪ t2) : tout dans t1 ou t2

(t1 ∪ t2) = (t1 ∩ t2) + t1_only + t2_only : tous dans les deux t1 et t2 plus tous dans t1 qui ne sont pas dans t2 et plus tous dans t2 qui ne sont pas dans t1 :

-- (t1 ∩ t2): all in both t1 and t2
select t1.value, t2.value
from t1 join t2 on t1.value = t2.value    
union all  -- And plus 
-- all in t1 that not exists in t2
select t1.value, null
from t1
where not exists( select 1 from t2 where t2.value = t1.value)    
union all  -- and plus
-- all in t2 that not exists in t1
select null, t2.value
from t2
where not exists( select 1 from t1 where t2.value = t1.value)

[SQL Fiddle]

26
répondu shA.t 2017-09-07 14:50:15

en SQLite vous devez faire ceci:

SELECT * 
FROM leftTable lt 
LEFT JOIN rightTable rt ON lt.id = rt.lrid 
UNION
SELECT lt.*, rl.*  -- To match column set
FROM rightTable rt 
LEFT JOIN  leftTable lt ON lt.id = rt.lrid
5
répondu Rami Jamleh 2015-05-28 04:43:45

aucune des réponses ci-dessus n'est en fait correcte, parce qu'elles ne suivent pas la sémantique lorsqu'il y a des valeurs dupliquées.

Pour une requête telle que (à partir de ce dupliquer ):

SELECT * FROM t1 FULL OUTER JOIN t2 ON t1.Name = t2.Name;

l'équivalent correct est:

SELECT t1.*, t2.*
FROM (SELECT name FROM t1 UNION  -- This is intentionally UNION to remove duplicates
      SELECT name FROM t2
     ) n LEFT JOIN
     t1
     ON t1.name = n.name LEFT JOIN
     t2
     ON t2.name = n.name;

si vous avez besoin que cela fonctionne avec les valeurs NULL (qui peuvent également être nécessaires), puis utiliser le NULL - opérateur de comparaison Sécuritaire, <=> plutôt que = .

4
répondu Gordon Linoff 2017-05-23 12:34:54

Modified shA.t de la requête pour plus de clarté:

-- t1 left join t2
SELECT t1.value, t2.value
FROM t1 LEFT JOIN t2 ON t1.value = t2.value   

    UNION ALL -- include duplicates

-- t1 right exclude join t2 (records found only in t2)
SELECT t1.value, t2.value
FROM t1 RIGHT JOIN t2 ON t1.value = t2.value
WHERE t2.value IS NULL 
3
répondu a20 2016-03-11 08:47:04

MySql n'a pas la syntaxe FULL-OUTER-JOIN. Vous devez imiter en faisant à la fois gauche joindre et droit joindre comme suit -

SELECT * FROM t1
LEFT JOIN t2 ON t1.id = t2.id  
UNION
SELECT * FROM t1
RIGHT JOIN t2 ON t1.id = t2.id

mais MySql n'a pas non plus de syntaxe de jointure droite. Selon MySql simplification de la jointure extérieure , la jointure droite est convertie en jointure gauche équivalente en commettant les t1 et t2 dans la clause FROM et ON dans la requête. Ainsi, L'Optimiseur de requête MySql traduit l'original requête dans le -

SELECT * FROM t1
LEFT JOIN t2 ON t1.id = t2.id  
UNION
SELECT * FROM t2
LEFT JOIN t1 ON t2.id = t1.id

maintenant, il n'y a aucun mal à écrire la requête originale telle quelle, Mais dites Si vous avez des prédicats comme la clause où, qui est un avant-joindre prédicate ou an et de prédire sur la ON clause, qui est un pendant-joindre prédicate, alors vous pourriez vouloir regardez le diable, qui est dans les détails.

MySql query optimizer vérifie régulièrement les prédicats s'ils sont null-rejeté . Null-Rejected Definition and Examples Maintenant, si vous avez fait la bonne jointure, mais avec où prédire sur la colonne de t1, alors vous pourriez être à un risque de tomber dans un null-rejeté scénario.

par exemple, La requête suivante -

SELECT * FROM t1
LEFT JOIN t2 ON t1.id = t2.id
WHERE t1.col1 = 'someValue'
UNION
SELECT * FROM t1
RIGHT JOIN t2 ON t1.id = t2.id
WHERE t1.col1 = 'someValue'

est traduit au suivi par le Query Optimizer -

SELECT * FROM t1
LEFT JOIN t2 ON t1.id = t2.id
WHERE t1.col1 = 'someValue'
UNION
SELECT * FROM t2
LEFT JOIN t1 ON t2.id = t1.id
WHERE t1.col1 = 'someValue'

ainsi l'ordre des tableaux a changé, mais le prédicat est toujours appliqué à t1, mais t1 est maintenant dans la clause "ON". Si t1.la col1 est définie comme NOT NULL colonne, alors cette requête sera null-rejeté .

toute jointure externe (gauche, droite, complète) qui est nulle-rejetée est convertie en jointure interne par MySql.

D'où les résultats vous pourriez vous attendre pourrait être complètement différent de ce que le MySql est de retour. Vous pensez peut-être que C'est un bug avec MySql droit rejoindre, mais ce n'est pas juste. C'est comme ça que fonctionne le MySQL query-optimizer. Ainsi, le promoteur responsable doit prêter attention à ces nuances lorsqu'il construit la requête.

3
répondu Akshayraj Kore 2018-09-13 20:15:51

vous pouvez faire ce qui suit:

(SELECT 
    *
FROM
    table1 t1
        LEFT JOIN
    table2 t2 ON t1.id = t2.id
WHERE
    t2.id IS NULL)
UNION ALL
 (SELECT 
    *
FROM
    table1 t1
        RIGHT JOIN
    table2 t2 ON t1.id = t2.id
WHERE
    t1.id IS NULL);
1
répondu lolo 2018-06-05 07:54:37
SELECT
    a.name,
    b.title
FROM
    author AS a
LEFT JOIN
    book AS b
    ON a.id = b.author_id
UNION
SELECT
    a.name,
    b.title
FROM
    author AS a
RIGHT JOIN
    book AS b
    ON a.id = b.author_id
0
répondu pltvs 2013-10-24 11:10:07

qu'avez-vous dit à propos de la solution Cross join ?

SELECT t1.*, t2.*
FROM table1 t1
INNER JOIN table2 t2 
ON 1=1;
0
répondu Super Mario 2018-07-01 14:34:59

Il est également possible, mais vous devez mentionner les mêmes noms de champs à sélectionner.

SELECT t1.name, t2.name FROM t1
LEFT JOIN t2 ON t1.id = t2.id
UNION
SELECT t1.name, t2.name FROM t2
LEFT JOIN t1 ON t1.id = t2.id
-1
répondu alamelu 2014-02-03 12:30:07

Mysql en tant que tel ne supporte aucune commande nommée FULL OUTER JOIN. Les trois jointures supportées sont INNER JOIN,LEFT JOIN et RIGHT JOIN.

vous pouvez cependant mettre en œuvre la jointure externe complète en utilisant la commande UNION comme

(requête de join de gauche) UNION (requête de join de droite)

par exemple, considérez l'exemple suivant où j'ai deux élèves de tables et des notes. Pour effectuer la jointure externe complète, j'exécute le code suivant:

SELECT * FROM students  
LEFT JOIN marks   
ON students.id = marks.id  
UNION ALL  
SELECT * FROM students 
RIGHT JOIN marks  
ON students.id = marks.id;
-1
répondu Jeet 2016-12-31 12:42:19

je fixe la réponse, et les travaux incluent toutes les lignes (basé sur la réponse de Pavle Lekic)

    (
    SELECT a.* FROM tablea a
    LEFT JOIN tableb b ON a.`key` = b.key
    WHERE b.`key` is null
    )
    UNION ALL
    (
    SELECT a.* FROM tablea a
    LEFT JOIN tableb b ON a.`key` = b.key
    where  a.`key` = b.`key`
    )
    UNION ALL
    (
    SELECT b.* FROM tablea a
    right JOIN tableb b ON b.`key` = a.key
    WHERE a.`key` is null
    );
-1
répondu Rubén Ruíz 2017-08-02 06:44:15

réponse:

SELECT * FROM t1 FULL OUTER JOIN t2 ON t1.id = t2.id;

peut être recréé comme suit:

 SELECT t1.*, t2.* 
 FROM (SELECT * FROM t1 UNION SELECT name FROM t2) tmp
 LEFT JOIN t1 ON t1.id = tmp.id
 LEFT JOIN t2 ON t2.id = tmp.id;

utilisant une UNION ou une UNION toutes les réponses ne couvrent pas le cas de bord lorsque les tables de base ont des entrées dupliquées.

explication:

il y a un cas limite qu'un syndicat ou un syndicat ne peut pas couvrir. Nous ne pouvons pas tester cela sur mysql car il ne supporte pas les

 WITH cte_t1 AS
 (
       SELECT 1 AS id1
       UNION ALL SELECT 2
       UNION ALL SELECT 5
       UNION ALL SELECT 6
       UNION ALL SELECT 6
 ),
cte_t2 AS
(
      SELECT 3 AS id2
      UNION ALL SELECT 4
      UNION ALL SELECT 5
      UNION ALL SELECT 6
      UNION ALL SELECT 6
)
SELECT  *  FROM  cte_t1 t1 FULL OUTER JOIN cte_t2 t2 ON t1.id1 = t2.id2;

This gives us this answer:

id1  id2
1  NULL
2  NULL
NULL  3
NULL  4
5  5
6  6
6  6
6  6
6  6

L'UNION de la solution:

SELECT  * FROM  cte_t1 t1 LEFT OUTER JOIN cte_t2 t2 ON t1.id1 = t2.id2
UNION    
SELECT  * FROM cte_t1 t1 RIGHT OUTER JOIN cte_t2 t2 ON t1.id1 = t2.id2

donne une réponse incorrecte:

 id1  id2
NULL  3
NULL  4
1  NULL
2  NULL
5  5
6  6

L'UNION de TOUS les solution:

SELECT  * FROM cte_t1 t1 LEFT OUTER join cte_t2 t2 ON t1.id1 = t2.id2
UNION ALL
SELECT  * FROM  cte_t1 t1 RIGHT OUTER JOIN cte_t2 t2 ON t1.id1 = t2.id2

est également incorrect.

id1  id2
1  NULL
2  NULL
5  5
6  6
6  6
6  6
6  6
NULL  3
NULL  4
5  5
6  6
6  6
6  6
6  6

attendu que cette requête:

SELECT t1.*, t2.*
FROM (SELECT * FROM t1 UNION SELECT name FROM t2) tmp 
LEFT JOIN t1 ON t1.id = tmp.id 
LEFT JOIN t2 ON t2.id = tmp.id;

donne le résultat suivant:

id1  id2
1  NULL
2  NULL
NULL  3
NULL  4
5  5
6  6
6  6
6  6
6  6

L'ordre est différent, mais sinon, correspond à la réponse correcte.

-2
répondu Angelos 2017-07-24 21:13:53

la norme SQL dit full join on est inner join on lignes union all lignes de table à gauche non appariées étendues par nulls union all lignes de table à droite étendues par nulls. C'est à dire inner join on lignes union all lignes left join on , mais pas inner join on union all lignes right join on , mais pas inner join on .

Ie left join on lignes union all right join on les lignes qui ne sont pas inner join on . Ou si vous connaissez votre résultat inner join on ne peut pas avoir nul dans un particulier colonne de droite puis" right join on les lignes non dans inner join on " sont des lignes dans right join on avec la condition on prolongée par and que la colonne is null .

c'est à dire de la même façon right join on union all approprié left join on lignes.

à Partir de Quelle est la différence entre "INNER JOIN" et "OUTER JOIN"? :

(SQL Standard 2006 SQL/Foundation 7.7 syntaxe Règles 1, Règles générales 1 b, 3 C & D, 5 B.)

-2
répondu philipxy 2018-08-11 22:09:28