【问题标题】:MySQL: Select All Dates In a Range Even If No Records PresentMySQL:选择范围内的所有日期,即使没有记录存在
【发布时间】:2010-11-06 00:30:19
【问题描述】:

我有一个用户数据库。我想创建一个基于用户群增长的图表。我现在的查询是:

SELECT DATE(datecreated), count(*) AS number FROM users 
WHERE DATE(datecreated) > '2009-06-21' AND DATE(datecreated) <= DATE(NOW())
GROUP BY DATE(datecreated) ORDER BY datecreated ASC

几乎返回了我想要的。如果我们一天有 0 个用户,那一天不会作为 0 值返回,它只是被跳过并返回至少有一个用户的第二天。我怎样才能得到类似(psuedo-response)的东西:

date1 5
date2 8
date3 0
date4 0
date5 9
etc...

带零的日期与其余日期按顺序显示在哪里?

谢谢!

【问题讨论】:

    标签: mysql date gaps-and-islands


    【解决方案1】:

    最好这样做:

    -- 7 Days:
    set @n:=date(now() + interval 1 day);
    SELECT qb.day_series as days , COALESCE(col_byte, 0) as Bytes from tbl1 qa
        right join (
            select (select @n:= @n - interval 1 day) day_series from tbl1 limit 7 ) as qb 
        on date(qa.Timestamp) = qb.day_series and 
    qa.Timestamp > DATE_SUB(curdate(), INTERVAL 7 day) order by qb.day_series asc
    
    -- 30 Days:
    set @n:=date(now() + interval 1 day);
    SELECT qb.day_series as days , COALESCE(col_byte, 0) as Bytes from tbl1 qa
        right join (
            select (select @n:= @n - interval 1 day) day_series from tbl1 limit 30 ) as qb 
        on date(qa.Timestamp) = qb.day_series and 
    qa.Timestamp > DATE_SUB(curdate(), INTERVAL 30 day) order by qb.day_series asc;
    

    或者没有像这样的变量:

    SELECT qb.day_series as days , COALESCE(col_byte, 0) as Bytes from tbl1 qa
    right join (
        select curdate() - INTERVAL a.a day as day_series from(
            select 0 as a union all select 1 union all select 2 union all 
            select 3 union all select 4 union all 
            select 5 union all select 6 union all select 7
        ) as a ) as qb
    on date(qa.Timestamp) = qb.day_series and
    qa.Timestamp > DATE_SUB(curdate(), INTERVAL 7 day) order by qb.day_series asc;
    

    【讨论】:

      【解决方案2】:

      查询是:

      SELECT qb.dy as yourday, COALESCE(count(yourcolumn), 0) as yourcount from yourtable qa 
      right join (
          select curdate() as dy    union
          select DATE_SUB(curdate(), INTERVAL 1 day) as dy     union
          select DATE_SUB(curdate(), INTERVAL 2 day) as dy     union
          select DATE_SUB(curdate(), INTERVAL 3 day) as dy     union
          select DATE_SUB(curdate(), INTERVAL 4 day) as dy     union
          select DATE_SUB(curdate(), INTERVAL 5 day) as dy     union
          select DATE_SUB(curdate(), INTERVAL 6 day) as dy        
          ) as qb 
      on qa.dates = qb.dy 
      and qa.dates > DATE_SUB(curdate(), INTERVAL 7 day)
      order by qb.dy asc;
      

      结果是:

      +------------+-----------+
      | yourday    | yourcount |
      +------------+-----------+
      | 2015-06-24 | 274339    |
      | 2015-06-25 |      0    |
      | 2015-06-26 |      0    |
      | 2015-06-27 |      0    |
      | 2015-06-28 | 134703    |
      | 2015-06-29 |  87613    |
      | 2015-06-30 |      0    |
      +------------+-----------+
      

      【讨论】:

        【解决方案3】:

        我希望你能解决剩下的问题。

        select  * from (
        select date_add('2003-01-01 00:00:00.000', INTERVAL n5.num*10000+n4.num*1000+n3.num*100+n2.num*10+n1.num DAY ) as date from
        (select 0 as num
           union all select 1
           union all select 2
           union all select 3
           union all select 4
           union all select 5
           union all select 6
           union all select 7
           union all select 8
           union all select 9) n1,
        (select 0 as num
           union all select 1
           union all select 2
           union all select 3
           union all select 4
           union all select 5
           union all select 6
           union all select 7
           union all select 8
           union all select 9) n2,
        (select 0 as num
           union all select 1
           union all select 2
           union all select 3
           union all select 4
           union all select 5
           union all select 6
           union all select 7
           union all select 8
           union all select 9) n3,
        (select 0 as num
           union all select 1
           union all select 2
           union all select 3
           union all select 4
           union all select 5
           union all select 6
           union all select 7
           union all select 8
           union all select 9) n4,
        (select 0 as num
           union all select 1
           union all select 2
           union all select 3
           union all select 4
           union all select 5
           union all select 6
           union all select 7
           union all select 8
           union all select 9) n5
        ) a
        where date >'2011-01-02 00:00:00.000' and date < NOW()
        order by date
        

        select n3.num*100+n2.num*10+n1.num as date
        

        你会得到一列数字从 0 到 max(n3)*100+max(n2)*10+max(n1)

        因为这里我们将 max n3 设为 3,所以 SELECT 将返回 399,加上 0 -> 400 条记录(日历中的日期)。

        您可以通过限制来调整您的动态日历,例如,从您必须的 min(date) 到 now()。

        【讨论】:

        • 我认为这是一个绝妙的技巧。得到我的投票。我假设,此查询可用于填充“日历”表。
        • 这是我见过的最干净的解决方案。真棒
        【解决方案4】:

        进一步思考,这样的东西应该是你想要的:

        CREATE TEMPORARY TABLE DateSummary1 ( datenew timestamp ) SELECT DISTINCT(DATE(datecreated)) as datenew FROM users;
        
        CREATE TEMPORARY TABLE DateSummary2 ( datenew timestamp, number int ) SELECT DATE(datecreated) as datenew, count(*) AS number FROM users 
        WHERE DATE(datecreated) > '2009-06-21' AND DATE(datecreated) <= DATE(NOW())
        GROUP BY DATE(datecreated) ORDER BY datecreated ASC;
        
        SELECT ds1.datenew,ds2.number FROM DateSummary1 ds1 LEFT JOIN DateSummary2 ds2 on ds1.datenew=ds2.datenew;
        

        这将为您提供第一个表中的所有日期,以及第二个表中的 count 汇总数据。您可能需要将 ds2.number 替换为 IF(ISNULL(ds2.number),0,ds2.number) 或类似的东西。

        【讨论】:

          【解决方案5】:

          对表进行右外部联接,将其命名为 tblCalendar,其中预先填充了您希望报告的日期。并加入日期字段。

          保罗

          【讨论】:

            【解决方案6】:

            This question 提出同样的问题。通常,公认的答案似乎是您要么在应用程序逻辑中执行此操作(将您拥有的内容读入数组,然后遍历数组并创建缺失的日期),要么使用填充了您希望的日期的临时表加入。

            【讨论】:

              猜你喜欢
              • 2017-05-25
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2018-06-01
              • 1970-01-01
              • 2020-04-01
              • 2014-10-04
              • 1970-01-01
              相关资源
              最近更新 更多