【问题标题】:MySQL - Combining multiple selects from same table into one result table with a group byMySQL - 将来自同一个表的多个选择组合到一个结果表中,其中一个 group by
【发布时间】:2013-04-14 16:56:55
【问题描述】:

我有一个仪表读数表,其中包含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 结果显示为自己的列?

【问题讨论】:

    标签: mysql sql database pivot


    【解决方案1】:

    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 with Demo

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

    【讨论】:

    • 我们得到了类似的答案。
    • @bozdoz 实际上我们的答案非常不同,您的版本使用的是int 年份,而我正在根据datetime 数据破译年份。不仅如此,我还包含了一个动态版本的查询,以允许未知的年数。
    • 我看到你最后做到了@bluefeet。为了简单起见,我在这一年中使用了 int 作为我的测试示例。
    • 谢谢,这是我使用的答案,因为它使用了 year(),这是我可以在本报告后面使用的东西。谢谢你们的帮助!
    【解决方案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 &gt;= '2009-01-01' AND readingDate &lt;= '2009-12-31' THEN readingValue END) 等来切换条件——但它应该可以工作。这是我在 sqlFiddle 上做的一个工作示例:http://sqlfiddle.com/#!2/6990e/29。输出为五列,每个meterNo的总和。

    【讨论】:

    • 我赞成这个版本,因为它返回 NULL,正如 OP 问题中的空白所建议的那样。
    • @phil - 也许,也许不是。一个NULL是一个NULL是一个NULL。它传达了数据的缺失,这对于区分 0(无移动)和数据缺失(尚未委托)很有用。只是大家猜测
    • @RichardTheKiwi 非常正确。你会在 DBA.se 上看到我,所以知道我知道 :P 也许只有我一个人,但大多数时候用空白而不是零的报告看起来不正确;)
    【解决方案3】:

    你可以这样做:

    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 子句。

    SEE FIDDLE

    【讨论】:

      猜你喜欢
      • 2014-11-22
      • 2016-11-10
      • 2022-11-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多