MySQL - 如何将列转为行?

问题描述 投票:0回答:3
ID | a  | b  | c 
1  | a1 | b1 | c1
2  | a2 | b2 | c2

如何将行重新组织为

ID
columntitle
value

1 | a1 | a
1 | b1 | b
1 | c1 | c
2 | a2 | a
2 | b2 | b
2 | c2 | c
mysql sql union unpivot lateral-join
3个回答
28
投票

您正在尝试 unpivot 数据。 MySQL 没有 unpivot 函数,因此您必须使用

UNION ALL
查询将列转换为行:

select id, 'a' col, a value
from yourtable
union all
select id, 'b' col, b value
from yourtable
union all
select id, 'c' col, c value
from yourtable

参见 SQL Fiddle with Demo

这也可以使用

CROSS JOIN
来完成:

select t.id,
  c.col,
  case c.col
    when 'a' then a
    when 'b' then b
    when 'c' then c
  end as data
from yourtable t
cross join
(
  select 'a' as col
  union all select 'b'
  union all select 'c'
) c

参见SQL Fiddle with Demo


6
投票

好久不见,MySQL 8.0.14 版本终于加入了对横向连接的支持——官方术语是lateral derived tables.

这是一个非常强大的功能,可以在多种情况下派上用场,包括将表列逆透视为行。

您可以按如下方式表达查询:

select t.id, x.*
from mytable t
cross join lateral (
    select a, 'a' 
    union all select b, 'b'
    union all select c, 'c'
) as x(col1, col2)

看起来这与典型的规范解决方案相比并没有太大区别——毕竟,我们仍在横向派生表中使用

union all
……但不要误会:这个查询扫描表仅一次,与另一种方法相反,后者需要对每一列进行一次扫描才能旋转。所以这更有效 - 并且随着表变大和/或更多列需要取消透视,性能增益会显着增加。

底线:如果您运行的是 MySQL 8.0.14 或更高版本,只需使用此技术。从那个版本开始,这是在 MYSQL 中取消透视的规范方法。

DB Fiddle 上的演示

样本数据:

编号 |一个 |乙 | C
-: | :- | :- | :-
 1 |一个1 | b1 | c1
 2 |一个2 | b2 | c2

查询结果:

编号 | col1 |列2
-: | :--- | :---
 1 |一个1 | A
 1 | b1 | b
 1 | c1 | C
 2 |一个2 | A
 2 | b2 | b
 2 | c2 | C

旁注

MySQL 8.0.19 添加了对

VALUES
语句 的支持,这可以通过消除在子查询中使用
union all
的需要来帮助进一步缩短查询(虽然我在这里没有看到任何性能提升,但这使得查询更整洁)。

不幸的是,从 8.0.21 版本开始,这个还不能工作——这可能被认为是一个错误——但也许会在未来的版本中……:

select t.id, x.*
from mytable t
cross join lateral (values 
    row(a, 'a'), 
    row(b, 'b'),
    row(c, 'c')
) as x(col1, col2);

3
投票

尝试使用UNION ALL.

SELECT ID, a, 'a' 
FROM tbl
WHERE ID = 1
UNION
SELECT ID, b, 'b' 
FROM tbl
WHERE ID = 2
© www.soinside.com 2019 - 2024. All rights reserved.