Mysql将列转换为行(数据透视表)

Posted

技术标签:

【中文标题】Mysql将列转换为行(数据透视表)【英文标题】:Mysql Convert Column to row (Pivot table ) 【发布时间】:2012-12-06 08:02:15 【问题描述】:

我有一张这样的桌子

+---+-----+----+----+----+----+
|id |month|col1|col2|col3|col4|
+---+-----+----+----+----+----+
|101|Jan  |A   |B   |NULL|B   |
+---+-----+----+----+----+----+
|102|feb  |C   |A   |G   |E   |
+---+-----+----+----+----+----+

然后我想创建这样的报告

+----+---+---+
|desc|jan|feb|
+----+---+---+
|col1|A  |C  |
+----+---+---+
|col2|B  |A  |
+----+---+---+
|col3|0  |G  |
+----+---+---+
|Col4|B  |E  |
+----+---+---+

有人可以帮忙吗?

【问题讨论】:

欢迎来到***。 This is a very common question。请花几分钟时间搜索档案。尝试先调整以前的答案之一。然后,如果您遇到问题,请在此处发布您的查询和任何错误。 mysql pivot row into dynamic number of columns的可能重复 【参考方案1】:

您需要首先对数据进行反透视,然后对其进行透视。但不幸的是,MySQL 没有这些函数,因此您需要使用 UNION ALL 查询 unpivot 和聚合函数以及 CASE 来复制它们。

unpivot 或UNION ALL 部分从您的 col1、col2 等获取数据并将其转换为多行:

select id, month, col1 value, 'col1' descrip
from yourtable
union all
select id, month, col2 value, 'col2' descrip
from yourtable
union all
select id, month, col3 value, 'col3' descrip
from yourtable
union all
select id, month, col4 value, 'col4' descrip
from yourtable

见SQL Fiddle with Demo。

结果:

|  ID | MONTH |  VALUE | DESCRIP |
----------------------------------
| 101 |   Jan |      A |    col1 |
| 102 |   feb |      C |    col1 |
| 101 |   Jan |      B |    col2 |
| 102 |   feb |      A |    col2 |
| 101 |   Jan | (null) |    col3 |
| 102 |   feb |      G |    col3 |
| 101 |   Jan |      B |    col4 |
| 102 |   feb |      E |    col4 |

然后您将其包装在子查询中以应用聚合和 CASE 以将其转换为您想要的格式:

select descrip, 
  max(case when month = 'jan' then value else 0 end) jan,
  max(case when month = 'feb' then value else 0 end) feb
from
(
  select id, month, col1 value, 'col1' descrip
  from yourtable
  union all
  select id, month, col2 value, 'col2' descrip
  from yourtable
  union all
  select id, month, col3 value, 'col3' descrip
  from yourtable
  union all
  select id, month, col4 value, 'col4' descrip
  from yourtable
) src
group by descrip

见SQL Fiddle with demo

结果是:

| DESCRIP | JAN | FEB |
-----------------------
|    col1 |   A |   C |
|    col2 |   B |   A |
|    col3 |   0 |   G |
|    col4 |   B |   E |

【讨论】:

谢谢你!超级有帮助。 非常感谢。如果yourtable 是来自子查询的派生表怎么办。我会用FROM (SELECT * FROM table WHERE name = 'condition') t1 之类的东西替换每个yourtable 吗? @Accountantم 是的,这正是你要做的 @Taryn - 你的解决方案太棒了。这对我帮助很大。为您的精彩回答投票。【参考方案2】:

虽然这个问题太老了,有人将其标记为“非常常见”,但人们似乎仍然发现它(包括我)并觉得它很有帮助。我开发了一个更通用的版本来取消旋转一行,并认为它可能对某人有所帮助。

SET @target_schema='schema';
SET @target_table='table';
SET @target_where='`id`=1';
SELECT
    GROUP_CONCAT(qry SEPARATOR ' UNION ALL ')
    INTO @sql
FROM (
    SELECT
        CONCAT('SELECT `id`,', QUOTE(COLUMN_NAME), ' AS `key`,`', COLUMN_NAME, '` AS `value` FROM `', @target_table, '` WHERE ', @target_where) qry
    FROM (
        SELECT `COLUMN_NAME` 
        FROM `INFORMATION_SCHEMA`.`COLUMNS` 
        WHERE `TABLE_SCHEMA`=@target_schema 
            AND `TABLE_NAME`=@target_table
    ) AS `A`
) AS `B`;
PREPARE s FROM @sql; EXECUTE s; DEALLOCATE PREPARE s;

我在 MySQL 8.x 服务器上使用此查询并将其聚合到那里的 JSON 对象,因此id, key, value 结果结构。

【讨论】:

以上是关于Mysql将列转换为行(数据透视表)的主要内容,如果未能解决你的问题,请参考以下文章

使用pivot SQL将列转换为行

使用php将mysql结果转换为数据透视表

Excel数据透视表MDX慢?

使用 PostgreSQL 创建数据透视表

sql 将列数据转换为行

SQL 反透视该行并获取订单号