【问题标题】:mysql pivot query results with GROUP BY带有 GROUP BY 的 mysql 透视查询结果
【发布时间】:2011-09-30 03:23:08
【问题描述】:

我有一个表格,其中包含要导出到 CSV 的数据。理想情况下,我想切换行和列,以便更好地分组数据。

为了进一步解释,目前,数据库看起来像这样..

data_id     data_timestamp         data_value    
--------------------------------------------
1           2011-07-07 00:01:00    0.400  
1           2011-07-07 00:02:00    0.500
1           2011-07-07 00:03:00    0.600
1           2011-07-07 00:04:00    0.700
2           2011-07-07 00:01:00    0.100  
2           2011-07-07 00:02:00    0.200
2           2011-07-07 00:03:00    0.250
2           2011-07-07 00:04:00    2.300

我想通过 data_timestamp 值对 data_value 进行分组,以便对时间戳进行分组,并且每个 data_id 的每个 data_value 都显示在一列中,而不是一行。

data_timestamp         input_1    input_2     
--------------------------------------------
2011-07-07 00:01:00    0.400      0.100  
2011-07-07 00:02:00    0.500      0.200
2011-07-07 00:03:00    0.600      0.250
2011-07-07 00:04:00    0.700      2.300

下面是我正在使用的查询...

SELECT d.data_timestamp, d.input_1, d.input_2
FROM (
    SELECT data_timestamp,
    IF(data_id=1,data_value,NULL) AS 'input_1',
    IF(data_id=2,data_value,NULL) AS 'input_2' FROM data
) AS d ORDER BY data_timestamp ASC

但这并不是我想要的,因为现在只要一个 data_id 没有值,就会有 NULL 值。 GROUP BY 似乎也对 data_value 进行了分组,这不是我想要的。

有什么建议吗?

编辑:

我已经尝试在外部查询中使用 WHERE d.input_1 IS NOT NULL,但不能完全得到结果..

在 WHERE 之前...

data_timestamp         input_1    input_2     
--------------------------------------------
2011-07-07 00:01:00    0.400      NULL
2011-07-07 00:01:00    NULL       0.100  
2011-07-07 00:02:00    0.500      NULL
2011-07-07 00:02:00    NULL       0.200
2011-07-07 00:03:00    0.600      NULL
2011-07-07 00:03:00    NULL       0.250
2011-07-07 00:04:00    0.700      NULL
2011-07-07 00:04:00    NULL       2.300

添加 WHERE d.input_1 IS NOT NULL 将删除 input_2 值..

data_timestamp         input_1    input_2     
--------------------------------------------
2011-07-07 00:01:00    0.400      NULL
2011-07-07 00:02:00    0.500      NULL
2011-07-07 00:03:00    0.600      NULL
2011-07-07 00:04:00    0.700      NULL

另外,实际上,我有大约 20 个 id 可以分组,所以对它们来说也不是最好的主意..

【问题讨论】:

  • 为什么不在外部查询中添加WHERE 子句来过滤NULL 值?
  • @Michael,我确实有一个 WHERE d.input_1 IS NOT NULL,它适用于第一个 id,但不适用于第二个。我已经编辑它来说明..
  • 那为什么不加AND d.input_2 IS NOT NULL呢?
  • 我试过了,但是根本不返回任何结果,因为当 input_1 和 input_2 都为 NULL 时不会发生。一个总是有一个值,当另一个是 NULL...
  • 那么你可以使用IF 来选择不为空的值。

标签: mysql csv pivot


【解决方案1】:

PIVOTing 做起来既不容易(也不好)。我更喜欢使用CASE:

SELECT d.data_timestamp
     , SUM( CASE WHEN data_id =  1 THEN data_value ELSE 0 END ) AS 'input_1'
     , SUM( CASE WHEN data_id =  2 THEN data_value ELSE 0 END ) AS 'input_2'
     ...
     , SUM( CASE WHEN data_id = 20 THEN data_value ELSE 0 END ) AS 'input_20'
FROM data 
GROUP BY data_timestamp
ORDER BY data_timestamp ASC

IF 也适用于 MySQL:

SELECT d.data_timestamp
     , SUM( IF(data_id =  1, data_value, 0) ) AS 'input_1'
     , SUM( IF(data_id =  2, data_value, 0) ) AS 'input_2'
     ...
     , SUM( IF(data_id = 20, data_value, 0) ) AS 'input_20'
FROM data 
GROUP BY data_timestamp
ORDER BY data_timestamp ASC

或者,您可以使用 20 级 JOIN

SELECT d.data_timestamp
     , d01.data_value AS 'input_1'
     , d02.data_value AS 'input_2'
     ...
     , d20.data_value AS 'input_20'
FROM
  ( SELECT DISTINCT d.data_timestamp
    FROM data
  ) AS d 
  LEFT JOIN data AS d01
    ON d01.data_timestamp = d.data_timestamp
    AND d01.data_id =  1
  LEFT JOIN data AS d02
    ON d02.data_timestamp = d.data_timestamp
    AND d02.data_id =  2
  ...                                   --- 20 JOINs
  LEFT JOIN data AS d20
    ON d20.data_timestamp = d.data_timestamp
    AND d20.data_id = 20
ORDER BY d.data_timestamp ASC

【讨论】:

  • 我不想使用 20 级连接(这让我很紧张),但你的 CASE(和 IF)实际上是我很久以前使用的(后来忘记了) .让我受益的是 SUM 的使用,它实际上并没有对所有分组结果求和。非常感谢!
  • @crawf:您可以通过 20 级连接进行测试。它可能会更快:)
  • 经过几次测试,它比中频解决方案略快。我很惊讶,我没想到加入这么多次会更快。再次感谢!
  • @crawf:欢迎使用大表进行测试,例如 100K 行等,以确保(并保留更快的)。如果有机会,您可以将它用于如此多的数据。
【解决方案2】:

只需将表连接到自身!

SELECT dt1.data_timestamp, dt1.input_1, dt2.input_2
FROM data_timestamp dt1
JOIN data_timestamp dt2 
    on dt1.data_timestamp = dt2.data_timestamp 
    and dt2.input_1 is null
WHERE dt1.input_2 is null;

请注意,此查询假定每个 input_1 值都存在 input_2 的值。如果不是这种情况,请使用LEFT JOINCROSS JOIN

【讨论】:

  • 如果我能接受两个答案,我会的!这就是我投票支持它的原因。问题是我有 20 个数据 ID 可以加入。使用你的解决方案,我需要有 20 个不同的连接,我不喜欢这些连接(并且不确定这会如何降低性能)。我不是故意不接受冒犯,这对于包含 2 个数据 ID 的表格来说是完美的!
猜你喜欢
  • 2020-02-06
  • 2014-04-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-15
  • 1970-01-01
  • 2011-08-05
相关资源
最近更新 更多