在日期范围之间选择并强制空行为0?

时间:2011-06-15 03:01:20

标签: mysql sql group-by datetime-generation

我有一张类似

的表格
expires    | value  
-------------------
2011-06-15 | 15  
2011-06-15 | 15  
2011-06-25 | 15  
2011-07-15 | 15  
2011-07-15 | 15  
2011-07-25 | 15  
2011-08-15 | 15  
2011-08-15 | 15  
2011-08-25 | 15

我想运行一个将吐出的查询

June   | 45  
July   | 45  
August | 45  

所以我的查询是

  SELECT SUM(amount) AS `amount`, 
         DATE_FORMAT(expires , '%M') AS `month`  
    FROM dealDollars 
   WHERE DATE(expires) BETWEEN DATE(NOW()) 
                           AND LAST_DAY(DATE(NOW()+INTERVAL 3 MONTH)) 
GROUP BY MONTH(expires)

哪个工作正常。但结果是,如果7月份没有行,那么7月就不会出现。

如何强制7月出现0作为其值?

4 个答案:

答案 0 :(得分:4)

没有简单的方法可以做到这一点。一种可能的方法是有一个名为months的表: 哪个将有12行:( 1月,2月,...,12月)

您可以使用您需要的查询连接Months表以获得所需的输出。

答案 1 :(得分:1)

一般consensus是你应该创建一个月份名表。以下是一个愚蠢的解决方案,可以作为一种解决方法。

你必须自己处理这些细节,但是你看过sub-queries in the from clause吗?

基本上,它会是这样的:

SELECT NVL(B.amount, 0) as `amount`, A.month as `month`
      FROM (SELECT 'January' as `month`
            UNION SELECT 'February' as `month`
            UNION SELECT 'March' as `month`...
            UNION SELECT 'DECEMBER' as `month`) as A
      LEFT JOIN
            (SELECT SUM(amount) AS `amount`, 
                    DATE_FORMAT(expires , '%M') AS `month`  
               FROM dealDollars 
               WHERE 
                  DATE(expires) BETWEEN 
                       DATE(NOW()) AND 
                       LAST_DAY(DATE(NOW()+INTERVAL 3 MONTH)) 
               GROUP BY MONTH(expires)) as B
            ON (A.MONTH = B.MONTH)

疯了,不是吗?

答案 2 :(得分:1)

MySQL没有递归功能,所以你不得不使用NUMBERS表技巧 -

  1. 创建一个只保存递增数字的表 - 使用auto_increment很容易做到:

    DROP TABLE IF EXISTS `example`.`numbers`;
    CREATE TABLE  `example`.`numbers` (
      `id` int(10) unsigned NOT NULL auto_increment,
       PRIMARY KEY  (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=latin1;
    
  2. 使用以下方法填充表格:

    INSERT INTO NUMBERS
      (id)
    VALUES
      (NULL)
    

    ...尽可能多的价值观。在这种情况下,INSERT语句需要至少运行3次。

  3. 使用DATE_ADD构建天数列表,根据NUMBERS.id值增加:

    SELECT x.dt
      FROM (SELECT DATE(DATE_SUB(CURRENT_DATE(), INTERVAL (n.id - 1) MONTH)) AS dt
              FROM numbers n
             WHERE DATE(DATE_SUB(CURRENT_DATE(), INTERVAL (n.id - 1) MONTH)) BETWEEN CURRENT_DATE()
                                                                                 AND LAST_DAY(CURRENT_DATE() +INTERVAL 3 MONTH))  ) x
    
  4. 使用OUTER JOIN获取所需的输出:

       SELECT x.dt,
              COUNT(*) AS total
         FROM (SELECT DATE(DATE_SUB(CURRENT_DATE(), INTERVAL (n.id - 1) MONTH)) AS dt
              FROM numbers n
             WHERE DATE(DATE_SUB(CURRENT_DATE(), INTERVAL (n.id - 1) MONTH)) BETWEEN CURRENT_DATE()
                                                                                 AND LAST_DAY(CURRENT_DATE() +INTERVAL 3 MONTH))  ) x
    LEFT JOIN YOUR_TABLE y ON y.date = x.dt
     GROUP BY x.dt
     ORDER BY x.dt
    
  5. 为什么是数字,而不是日期?

    简单 - 可以根据数字生成日期,就像我提供的示例一样。它还意味着使用单个表,而不是每个数据类型一个。

答案 3 :(得分:0)

select MONTHNAME(expires) as month_name,sum(`value`) from Table1
group by month_name order by null;

fiddle