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
您正在尝试 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
这也可以使用
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
好久不见,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 中取消透视的规范方法。
样本数据:
编号 |一个 |乙 | 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
旁注
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);
尝试使用UNION ALL.
SELECT ID, a, 'a'
FROM tbl
WHERE ID = 1
UNION
SELECT ID, b, 'b'
FROM tbl
WHERE ID = 2