【问题标题】:MySQL Union into New ColumnMySQL 并入新列
【发布时间】:2017-06-09 17:59:50
【问题描述】:

假设我有两张桌子:

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 |
+------+------+

a.idb.id 上的GROUP BY 丢失未分组的列中的一个值。

每张桌子的大小可以不同。如果一个表比另一个大,NULL 值应该放在较短的列中。

【问题讨论】:

  • 表格的行数是否相同?例如,如果 a 的行数比 b 多怎么办?
  • 通过执行两个查询并将它们组合到 php 或您使用的任何语言中,可能会有一个更简单的解决方案。我很想知道您要解决的现实问题?
  • @leeyuiwah 每张桌子的大小可以变化。

标签: mysql join union


【解决方案1】:

不平凡的&

现在测试:SQL FIDDLE 现在更新以处理包括两个表中的所有记录的要求。 SQL Fiddle

我会使用用户变量为每个表中的每一行分配一个特定的行号,然后加入用户变量。加入伪列值“nothing”不起作用的原因是,如您所见,它对另一个表中的每个值使用 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

我还应用了 order by,以便每个表的较低 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

注意unionunion all

Union 执行了一个 distinct 操作,它将删除使用 union all 时不会发生的重复项

【讨论】:

  • SELECT @row... 语句也需要它们自己的别名,但除此之外,这似乎可行。
  • 这在表行计数匹配时有效,但无法处理两个表中不匹配的行计数。
  • 同意这就是我陈述以下两件事的原因: 1) 这假设如果两个表的行不相等,则具有更多记录的表将切断,消除更高的行号是可以接受的。 2)如果你愿意,你可以使用外部(左,右)连接,以便显示具有更多 ID 的表的所有记录,但你必须先知道哪个表有更多。
  • 或者您可以使用两个外连接和一个 UNION,就像我在回答中所做的那样。
  • 嗯...模糊的要求导致不同的答案。
【解决方案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]>

【讨论】:

  • 这在表行计数匹配时有效,但无法处理两个表中不匹配的行计数。
  • 不正确,如果 A 的记录多于 B,或者如果 B 的记录多于 A,则它们不匹配(但也许没关系,它们只需要最低行数的组合)表...
  • 我通过插入其中一列进行了测试,它正确地将 NULL 附加到较短的列。
  • @xQbert 感谢您的更正。我在回答中使用了两个外连接和一个 UNION 来处理这两种情况。
【解决方案3】:

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

  1. 行 ID(以便您可以连接两个表中的匹配行)
  2. 完全外连接(涵盖 table_A 有更多行或 table_B 有更多行的两种情况)

为了解决这些缺失的功能,您可以使用如下查询:

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

【讨论】:

    【解决方案4】:

    我结合了几个答案:

    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)
    

    第一个 union 获得最大行数(如果两个表的行数不同),然后我们可以简单地将其连接到编号的表。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-02-25
      • 2012-10-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多