Disons que j'ai deux tables:

table_A    table_B
+----+     +----+
| id |     | id |
+----+     +----+
| 1  |     | 3  |
| 2  |     | 4  |
+----+     +----+ 

Ce que je veux, c'est le UNION des tables, mais avec les enregistrements de table_B comme colonne séparée, plutôt que des lignes supplémentaires. Il n'y a pas besoin de corrélation entre les lignes, comme dans le cas d'un JOIN.

Un exemple d'ensemble de résultats ressemblerait à ceci:

+------+------+
| a.id | b.id |
+------+------+
| 1    | 3    |
| 2    | 4    |
+------+------+

Je peux me rapprocher

SELECT a.id, b.id FROM 
(SELECT id, 'nothing' from table_A) a JOIN 
(SELECT id, 'nothing' from table_B) b ON a.nothing = b.nothing

Mais cela crée deux fois plus de lignes que nécessaire:

+------+------+
| a.id | b.id |
+------+------+
|    1 |    3 |
|    2 |    3 |
|    1 |    4 |
|    2 |    4 |
+------+------+

Et GROUP BY sur a.id ou b.id perd l'une des valeurs de la colonne qui n'est pas groupée.

La taille de chaque table peut varier. Si une table est plus grande que l'autre, les valeurs NULL doivent être placées dans la colonne la plus courte.

2
Jimmy P 24 janv. 2017 à 21:44

4 réponses

Meilleure réponse

Non trivial et

Et maintenant testé: SQL FIDDLE Et maintenant mis à jour pour gérer l'exigence d'inclure tous les enregistrements des deux tables. SQL Fiddle

J'attribuerais à chaque ligne de chaque table un numéro de ligne spécifique en utilisant une variable utilisateur, puis je me joindrais à la variable utilisateur. La raison pour laquelle la jointure sur une valeur de pseudo-colonne `` rien '' ne fonctionne pas est que, comme vous le voyez, elle utilise CHAQUE ID une fois pour chaque valeur de l'autre table, ce qui entraîne un 1: M lorsque vous avez besoin d'un 1: 1. En attribuant un numéro de ligne, nous garantissons que chaque ligne n'est utilisée qu'une seule fois; donc une relation 1: 1.

Cela suppose que si les deux tables ont des lignes inégales, la table ayant plus d'enregistrements sera coupée en éliminant les numéros de lignes les plus élevés est acceptable.

Si vous le souhaitez, vous pouvez utiliser une jointure externe (gauche, droite) pour que tous les enregistrements de la table avec plus d'identifiants s'affichent, mais vous devez d'abord savoir quelle table en a le plus.

SELECT C.ID, D.ID
FROM (SELECT id, @row:=@row+1  RN
      FROM table_A
      CROSS JOIN (select @row:=0) a
      ORDER BY ID) C
INNER JOIN (SELECT id, @row2:=@row2+1 RN
            FROM table_B
            CROSS JOIN (select @row2:=0) b
            ORDER BY ID) D
on C.RN = D.RN

J'ai également appliqué un ordre par afin que les identifiants inférieurs de chaque table soient alignés.

Maintenant, si vous ne savez pas quelle table aura plus d'enregistrements ...

Vous pouvez simuler une jointure externe complète dans MYSQL avec les éléments suivants ...

SELECT C.ID, D.ID
FROM (SELECT id, @row:=@row+1  RN
      FROM table_A
      CROSS JOIN (select @row:=0) a
      ORDER BY ID) C
LEFT JOIN (SELECT id, @row2:=@row2+1 RN
            FROM table_B
            CROSS JOIN (select @row2:=0) b
            ORDER BY ID) D
on C.RN = D.RN

UNION

SELECT C.ID, D.ID
FROM (SELECT id, @row:=@row+1  RN
      FROM table_A
      CROSS JOIN (select @row:=0) a
      ORDER BY ID) C
RIGHT JOIN (SELECT id, @row2:=@row2+1 RN
            FROM table_B
            CROSS JOIN (select @row2:=0) b
            ORDER BY ID) D
on C.RN = D.RN

Remarque union vs union all

Union fait une distinction qui supprimera les doublons qui ne se produiraient pas lors de l'utilisation d'un union all

3
xQbert 24 janv. 2017 à 19:13

Vous pouvez également le faire avec une requête comme celle-ci:

SELECT ra.id, rb.id
FROM (
    select @anr:=(@anr+1) as nr, a.* from table_a  a JOIN (SELECT @anr:=0 ) as init ) ra
LEFT JOIN (
    select @bnr:=(@bnr+1) as nr, b.* from table_b  b JOIN (SELECT @bnr:=0 ) as init ) rb
    ON ra.nr = rb.nr;

échantillon

MariaDB [l]> select * from table_a;
+----+
| id |
+----+
|  1 |
|  2 |
+----+
2 rows in set (0.00 sec)

MariaDB [l]> select * from table_b;
+----+
| id |
+----+
|  2 |
|  4 |
+----+
2 rows in set (0.00 sec)

MariaDB [l]> SELECT ra.id, rb.id
    -> FROM (
    ->     select @anr:=(@anr+1) as nr, a.* from table_a  a JOIN (SELECT @anr:=0 ) as init ) ra
    -> LEFT JOIN (
    ->     select @bnr:=(@bnr+1) as nr, b.* from table_b  b JOIN (SELECT @bnr:=0 ) as init ) rb
    ->     ON ra.nr = rb.nr;
+----+------+
| id | id   |
+----+------+
|  1 |    2 |
|  2 |    4 |
+----+------+
2 rows in set (0.00 sec)

MariaDB [l]>
2
Bernd Buffen 24 janv. 2017 à 19:00

Vous avez besoin de deux fonctionnalités que MySQL n'a pas:

  1. ID de ligne (afin que vous puissiez joindre les lignes correspondantes des deux tables)
  2. Jointure externe complète (pour couvrir les deux cas où table_A a plus de lignes, ou lorsque table_B a plus de lignes)

Afin de contourner ces fonctionnalités manquantes, vous pouvez utiliser une requête comme celle-ci:

select a.id,b.id
from 
(
SELECT @rownum:=@rownum + 1 as row_number, t1.id
FROM ( 
   select id from table_A order by id
) t1,
(SELECT @rownum := 0) r1
) a
left outer join 
(
SELECT @rownum2:=@rownum2 + 1 as row_number, t2.id
FROM ( 
   select id from table_B order by id
) t2,
(SELECT @rownum2 := 0) r2
) b on b.row_number = a.row_number
union 
select c.id,d.id
from 
(
SELECT @rownum3:=@rownum3 + 1 as row_number, t3.id
FROM ( 
   select id from table_A order by id
) t3,
(SELECT @rownum3 := 0) r3
) c
right outer join 
(
SELECT @rownum4:=@rownum4 + 1 as row_number, t4.id
FROM ( 
   select id from table_B order by id
) t4,
(SELECT @rownum4 := 0) r4
) d on d.row_number = c.row_number
2
Ike Walker 24 janv. 2017 à 19:06

J'ai combiné quelques réponses:

SELECT A.id, B.id FROM
(
  SELECT @ca:=(@ca+1) as c FROM table_a JOIN (SELECT @ca:=0) as init
  UNION
  SELECT @cb:=(@cb+1) as c FROM table_b JOIN (SELECT @cb:=0) as init
) as maxrows
LEFT JOIN 
(
  SELECT @c2:=(@c2+1) as c2, id FROM table_a JOIN (SELECT @c2:=0) as init
) as A on (c = c2)
LEFT JOIN 
(
  SELECT @c3:=(@c3+1) as c3, id  FROM table_b JOIN (SELECT @c3:=0) as init
) as B on (c = c3)

La première union obtient le nombre maximum de lignes (dans le cas où les deux tables ont un nombre de lignes différent), puis nous pouvons simplement la joindre aux tables numérotées.

0
TimoSolo 24 janv. 2017 à 21:05