我试着搜索帖子,但我只找到SQL Server/Access的解决方案。我需要一个解决方案在MySQL (5.X)。

我有一个表(称为历史)3列:hostid, itemname, itemvalue。 如果我执行select (select * from history),它会返回

   +--------+----------+-----------+
   | hostid | itemname | itemvalue |
   +--------+----------+-----------+
   |   1    |    A     |    10     |
   +--------+----------+-----------+
   |   1    |    B     |     3     |
   +--------+----------+-----------+
   |   2    |    A     |     9     |
   +--------+----------+-----------+
   |   2    |    C     |    40     |
   +--------+----------+-----------+

如何查询数据库以返回类似的内容

   +--------+------+-----+-----+
   | hostid |   A  |  B  |  C  |
   +--------+------+-----+-----+
   |   1    |  10  |  3  |  0  |
   +--------+------+-----+-----+
   |   2    |   9  |  0  |  40 |
   +--------+------+-----+-----+

当前回答

另一个选择,尤其有用,如果你有很多项,你需要枢轴是让mysql为你构建查询:

SELECT
  GROUP_CONCAT(DISTINCT
    CONCAT(
      'ifnull(SUM(case when itemname = ''',
      itemname,
      ''' then itemvalue end),0) AS `',
      itemname, '`'
    )
  ) INTO @sql
FROM
  history;
SET @sql = CONCAT('SELECT hostid, ', @sql, ' 
                  FROM history 
                   GROUP BY hostid');

PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

小提琴 添加了一些额外的值,以看到它的工作

GROUP_CONCAT的默认值为1000,因此如果您有一个非常大的查询,请在运行它之前更改此参数

SET SESSION group_concat_max_len = 1000000;

测试:

DROP TABLE IF EXISTS history;
CREATE TABLE history
(hostid INT,
itemname VARCHAR(5),
itemvalue INT);

INSERT INTO history VALUES(1,'A',10),(1,'B',3),(2,'A',9),
(2,'C',40),(2,'D',5),
(3,'A',14),(3,'B',67),(3,'D',8);

  hostid    A     B     C      D
    1     10      3     0      0
    2     9       0    40      5
    3     14     67     0      8

其他回答

我编辑阿贡Sagita的答案从子查询加入。 我不确定这两种方式有多大区别,但只是作为另一个参考。

SELECT  hostid, T2.VALUE AS A, T3.VALUE AS B, T4.VALUE AS C
FROM TableTest AS T1
LEFT JOIN TableTest T2 ON T2.hostid=T1.hostid AND T2.ITEMNAME='A'
LEFT JOIN TableTest T3 ON T3.hostid=T1.hostid AND T3.ITEMNAME='B'
LEFT JOIN TableTest T4 ON T4.hostid=T1.hostid AND T4.ITEMNAME='C'
SELECT 
    hostid, 
    sum( if( itemname = 'A', itemvalue, 0 ) ) AS A,  
    sum( if( itemname = 'B', itemvalue, 0 ) ) AS B, 
    sum( if( itemname = 'C', itemvalue, 0 ) ) AS C 
FROM 
    bob 
GROUP BY 
    hostid;

我把它变成Group By hostId,然后它只会显示第一行的值, 如:

A   B  C
1  10
2      3

使用子查询

SELECT  hostid, 
    (SELECT VALUE FROM TableTest WHERE ITEMNAME='A' AND hostid = t1.hostid) AS A,
    (SELECT VALUE FROM TableTest WHERE ITEMNAME='B' AND hostid = t1.hostid) AS B,
    (SELECT VALUE FROM TableTest WHERE ITEMNAME='C' AND hostid = t1.hostid) AS C
FROM TableTest AS T1
GROUP BY hostid

但如果子查询结果超过一行,则会出现问题,在子查询中使用进一步的聚合函数

如果你可以使用MariaDB,有一个非常非常简单的解决方案。

自MariaDB-10.02以来,添加了一个新的存储引擎CONNECT,可以帮助我们将另一个查询或表的结果转换为数据透视表,就像你想要的那样: 你可以看看这些文件。

首先安装connect存储引擎。

现在我们的表的主列是itemname,每一项的数据都位于itemvalue列中,所以我们可以使用这个查询得到结果数据透视表:

create table pivot_table
engine=connect table_type=pivot tabname=history
option_list='PivotCol=itemname,FncCol=itemvalue';

现在我们可以从数据透视表中选择我们想要的:

select * from pivot_table

详情请点击这里