1

我有一个仪表读数表,其中包含一个meterNo、readingValue 和 readingDate。

我想显示每年每米读数的总和。

例如:

SELECT meterNo, SUM(readingValue) '2009' FROM readings
WHERE readingDate >= '2009-01-01' AND readingDate <= '2009-12-31'
GROUP BY meterNo;

将显示表格:

   meterNo  2009
   --------------
     4       50
     5       5
     12      30
     13      63
     18      18
     26      484
     27      21
     28      510
     29      28

这就是我想要的,它显示了 2009 年每个仪表的总读数值。但是,我需要结果表来显示每年的一列。所以它会是这样的:

   meterNo  2009  2010  2011  2012
   --------------------------------
     1             20    35     50
     2                   45     35
     3                   50     60
     4       50    35    20     30
     5       5     10    10     15
     6                          30

等等...

我可以重用查询的 where 部分:

WHERE readingDate >= '2009-01-01' AND readingDate <= '2009-12-31'

并且只需更改每年的日期,但是如何在一个结果表中将每个 WHERE 结果显示为自己的列?

4

3 回答 3

7

MySQL 没有 PIVOT 函数,但您可以使用带有CASE表达式的聚合函数将数据行转换为列。

如果您的 数量有限years,则可以对查询进行硬编码:

select meterNo,
  sum(case when year(readingDate) = 2009 then readingValue else 0 end) `2009`,
  sum(case when year(readingDate) = 2010 then readingValue else 0 end) `2010`,
  sum(case when year(readingDate) = 2011 then readingValue else 0 end) `2011`,
  sum(case when year(readingDate) = 2012 then readingValue else 0 end) `2012`,
  sum(case when year(readingDate) = 2013 then readingValue else 0 end) `2013`
from readings
group by meterno;

请参阅带有演示的 SQL Fiddle

但是,如果您将有未知数量的值或随着新年添加到数据库中要调整的查询,那么您可以使用准备好的语句来生成动态 SQL:

SET @sql = NULL;
SELECT
  GROUP_CONCAT(DISTINCT
    CONCAT(
      'sum(CASE WHEN year(readingDate) = ',
      year(readingDate),
      ' THEN readingValue else 0 END) AS `',
      year(readingDate), '`'
    )
  ) INTO @sql
FROM readings;

SET @sql 
  = CONCAT('SELECT meterno, ', @sql, ' 
            from readings
            group by meterno');

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

请参阅SQL Fiddle with Demo。两者都给出结果:

| METERNO | 2009 | 2010 | 2012 | 2013 | 2011 |
----------------------------------------------
|       1 |   90 |  180 |    0 |   90 |   90 |
|       2 |   50 |    0 |   90 |    0 |    0 |
|       3 |   80 |   40 |   90 |   90 |    0 |

作为旁注,如果您想null在没有值而不是零的行中显示,那么您可以删除else 0(参见Demo

于 2013-04-21T21:33:27.797 回答
2

您可以使用CASE WHEN来执行此操作。它允许您根据多个条件对多个值求和。在您的示例中,您可以执行以下操作(我简化了示例,因为我无权访问您的实际数据):

SELECT meterNo, 
sum(CASE WHEN readingDate = 2009 THEN readingValue END) as '2009',
sum(CASE WHEN readingDate = 2010 THEN readingValue END) as '2010',
sum(CASE WHEN readingDate = 2011 THEN readingValue END) as '2011',
sum(CASE WHEN readingDate = 2012 THEN readingValue END) as '2012'
FROM readings
GROUP BY meterNo

您需要使用自己的sum(CASE WHEN readingDate >= '2009-01-01' AND readingDate <= '2009-12-31' THEN readingValue END)- 等来切换条件 - 但它应该可以工作。这是我在 sqlFiddle 上做的一个工作示例:http ://sqlfiddle.com/#!2/6990e/29 。输出是五列,每个meterNo 的总和。

于 2013-04-21T21:31:42.113 回答
0

你可以这样做:

SELECT 
    meterNo, SUM(readingValue) AS `total`, YEAR(readingDate)
FROM 
    readings
GROUP BY 
    meterNo, YEAR(readingDate);

结果:

METERNO     TOTAL   YEAR(READINGDATE)
1           90      2009
1           90      2010
2           50      2009
3           80      2009
3           40      2010

还要注意如何使用YEAR函数而不是你拥有的 where 子句。

见小提琴

于 2013-04-21T21:07:09.583 回答