如何在GROUP BY之间插入其他值

时间:2009-09-16 16:58:23

标签: sql mysql

我目前正在使用MySQL进行月度报告。我有一个名为“monthly”的表,看起来像这样:

  id |         date        | amount

  10 | 2009-12-01 22:10:08 | 7 
  9  | 2009-11-01 22:10:08 | 78 
  8  | 2009-10-01 23:10:08 | 5 
  7  | 2009-07-01 21:10:08 | 54 
  6  | 2009-03-01 04:10:08 | 3 
  5  | 2009-02-01 09:10:08 | 456 
  4  | 2009-02-01 14:10:08 | 4 
  3  | 2009-01-01 20:10:08 | 20 
  2  | 2009-01-01 13:10:15 | 10 
  1  | 2008-12-01 10:10:10 | 5 

然后,当我每月报告(基于每年的每月)时,我会得到类似的结果。

yearmonth |总

2008-12   | 5 
2009-01   | 30 
2009-02   | 460 
2009-03   | 3 
2009-07   | 54 
2009-10   | 5 
2009-11   | 78 
2009-12   | 7 

我使用此查询来获得结果:

SELECT substring(date,1,7)AS yearmonth,sum(amount)AS total 来自monthly GROUP BY substring(date,1,7)

但我需要这样的事情:

yearmonth |总

2008-01   | 0 
2008-02   | 0 
2008-03   | 0 
2008-04   | 0 
2008-05   | 0 
2008-06   | 0 
2008-07   | 0 
2008-08   | 0 
2008-09   | 0
2008-10   | 0 
2008-11   | 0 
2008-12   | 5 
2009-01   | 30 
2009-02   | 460 
2009-03   | 3 
2009-05   | 0
2009-06   | 0
2009-07   | 54 
2009-08   | 0
2009-09   | 0
2009-10   | 5 
2009-11   | 78 
2009-12   | 7 

显示没有任何价值的月份的零的东西。甚至可以在MySQL查询中执行此操作吗?

2 个答案:

答案 0 :(得分:4)

你应该用它生成一个虚拟行源和LEFT JOIN

SELECT  *
FROM    (
        SELECT  1 AS month
        UNION ALL
        SELECT  2
        … 
        UNION ALL
        SELECT  12 
        ) months
CROSS JOIN
        (
        SELECT  2008 AS year
        UNION ALL
        SELECT  2009 AS year
        ) years
LEFT JOIN
        mydata m
ON      m.date >= CONCAT_WS('.', year, month, 1)
        AND m.date < CONCAT_WS('.', year, month, 1) + INTERVAL 1 MONTH
GROUP BY
        year, month

您可以在磁盘上创建这些表,而不是每次都生成它们。

MySQL是四大系统中唯一能够轻松生成任意结果集的系统。

OracleSQL ServerPostgreSQL分别有{CONNECT BY,递归CTEgenerate_series

答案 1 :(得分:0)

Quassnoi是对的,我会添加一条关于如何识别你需要什么的评论:

您希望在结果中使用“2008-01”,但源表中没有任何日期在2008年1月。结果集必须来自您查询的表,因此显而易见的结论是您需要一个额外的表 - 包含您希望作为结果一部分的每个月的一个。