我将添加一个更长、更详细的说明来说明解决此问题所需的步骤。如果太长,我深表歉意。
我将从您给出的基础开始,并用它来定义几个术语,我将在本文的其余部分使用这些术语。这将是基表:
select * from history;
+--------+----------+-----------+
| hostid | itemname | itemvalue |
+--------+----------+-----------+
| 1 | A | 10 |
| 1 | B | 3 |
| 2 | A | 9 |
| 2 | C | 40 |
+--------+----------+-----------+
这将是我们的目标,漂亮的数据透视表:
select * from history_itemvalue_pivot;
+--------+------+------+------+
| hostid | A | B | C |
+--------+------+------+------+
| 1 | 10 | 3 | 0 |
| 2 | 9 | 0 | 40 |
+--------+------+------+------+
值在history.hostid
列将成为y-values在数据透视表中。值在history.itemname
列将成为x-values(出于显而易见的原因)。
当我必须解决创建数据透视表的问题时,我使用三步过程来解决它(还有可选的第四步):
- 选择感兴趣的列,即y-values and x-values
- 用额外的列扩展基表——每列一个x-value
- 对扩展表进行分组和聚合——每个表一组y-value
- (可选)美化聚合表
让我们将这些步骤应用于您的问题,看看会得到什么:
第 1 步:选择感兴趣的列。在想要的结果中,hostid
提供了y-values and itemname
提供了x-values.
步骤 2:使用额外列扩展基表。我们通常需要每个 x 值一列。回想一下我们的 x 值列是itemname
:
create view history_extended as (
select
history.*,
case when itemname = "A" then itemvalue end as A,
case when itemname = "B" then itemvalue end as B,
case when itemname = "C" then itemvalue end as C
from history
);
select * from history_extended;
+--------+----------+-----------+------+------+------+
| hostid | itemname | itemvalue | A | B | C |
+--------+----------+-----------+------+------+------+
| 1 | A | 10 | 10 | NULL | NULL |
| 1 | B | 3 | NULL | 3 | NULL |
| 2 | A | 9 | 9 | NULL | NULL |
| 2 | C | 40 | NULL | NULL | 40 |
+--------+----------+-----------+------+------+------+
请注意,我们没有更改行数——我们只是添加了额外的列。还要注意图案NULL
s——一行itemname = "A"
新列具有非空值A
,以及其他新列的空值。
步骤3:对扩展表进行分组聚合。我们需要group by hostid
,因为它提供了 y 值:
create view history_itemvalue_pivot as (
select
hostid,
sum(A) as A,
sum(B) as B,
sum(C) as C
from history_extended
group by hostid
);
select * from history_itemvalue_pivot;
+--------+------+------+------+
| hostid | A | B | C |
+--------+------+------+------+
| 1 | 10 | 3 | NULL |
| 2 | 9 | NULL | 40 |
+--------+------+------+------+
(请注意,现在每个 y 值一行。)好的,我们快到了!我们只需要摆脱那些丑陋的NULL
s.
第四步:美化。我们将用零替换任何空值,以便结果集看起来更好:
create view history_itemvalue_pivot_pretty as (
select
hostid,
coalesce(A, 0) as A,
coalesce(B, 0) as B,
coalesce(C, 0) as C
from history_itemvalue_pivot
);
select * from history_itemvalue_pivot_pretty;
+--------+------+------+------+
| hostid | A | B | C |
+--------+------+------+------+
| 1 | 10 | 3 | 0 |
| 2 | 9 | 0 | 40 |
+--------+------+------+------+
我们就完成了——我们已经使用 MySQL 构建了一个漂亮的数据透视表。
应用此程序时的注意事项:
- 在额外的列中使用什么值。我用了
itemvalue
在这个例子中
- 在额外的列中使用什么“中性”值。我用了
NULL
,但也可能是0
or ""
,根据您的具体情况
- 分组时使用什么聚合函数。我用了
sum
, but count
and max
也经常使用(max
在构建分布在多行中的单行“对象”时经常使用)
- 使用多列作为 y 值。此解决方案不限于使用单个列作为 y 值 - 只需将额外的列插入
group by
条款(并且不要忘记select
them)
已知限制:
- 此解决方案不允许数据透视表中有 n 列——扩展基表时需要手动添加每个数据透视列。因此,对于 5 或 10 个 x 值,此解决方案很好。 100块,不太好。有一些使用存储过程生成查询的解决方案,但它们很丑陋并且很难正确执行。当数据透视表需要有很多列时,我目前不知道解决这个问题的好方法。