MySQL联盟进入新专栏

时间:2017-01-24 18:44:49

标签: mysql join union

说我有两张桌子:

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

我想要的是表的UNION,但是将table_B中的记录作为单独的列,而不是其他行。行之间不需要任何关联,例如JOIN

示例结果集如下所示:

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

我可以接近

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

但是这会产生两倍的行数:

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

GROUP BYa.id上的b.id会丢失未归类的列中的一个值。

每张桌子的大小可能会有所不同。如果一个表大于另一个表,则NULL值应放在较短的列中。

4 个答案:

答案 0 :(得分:3)

非平凡&

现在已经过测试:SQL FIDDLE 现在更新以处理包含来自两个表的所有记录的要求。 SQL Fiddle

我会使用用户变量为每个表中的每一行指定一个特定的行号,然后加入用户变量。加入伪列值“无”的原因是,如您所见,它对另一个表中的每个值使用一次EACH ID,​​因此当您需要1:1时会产生1:M。通过分配行号,我们保证每行只使用一次;因此是1:1的关系。

假设两个表都有不相等的行,那么具有更多记录的表将被截止,从而消除较高的行数是可以接受的。

如果您愿意,可以使用外部(左,右)连接,以便显示包含更多ID的表的所有记录,但您必须知道哪个表具有更多的第一个。

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

我还应用了一个订单,以便每个表的低ID对齐。

现在,如果您不知道哪个表会有更多记录......

您可以使用以下内容模拟MYSQL中的完整外部联接...

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

请注意union vs union all

Union做了一个与众不同的内容,它将删除使用union all

时不会发生的重复项

答案 1 :(得分:2)

您也可以使用以下查询执行此操作:

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;

<强>样品

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 :(得分:2)

您需要MySQL没有的两个功能:

  1. 行ID(因此您可以加入两个表中的匹配行)
  2. 全外连接(涵盖table_A有更多行的情况,或者table_B有更多行的情况)
  3. 为了解决这些缺失的功能,您可以使用如下查询:

    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
    

答案 3 :(得分:0)

我结合了几个答案:

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)

第一个联合获取最大行数(如果两个表具有不同的行数),然后我们可以简单地将它连接到编号表。