【问题标题】:group by year, month with 2 datefields conditions按年、月分组,有 2 个日期字段条件
【发布时间】:2014-11-20 09:48:15
【问题描述】:

我正在努力解决这个问题。

我有一个包含 3 列的表格:

id, startDate, endDate

1, 2014-01-01, 2014-02-02

2, 2014-04-03, NULL

3, 2014-02-02, 2014-05-03

现在我想计算所有具有特殊条件的 id: 例如月份可能:

SELECT COUNT(*) FROM Table WHERE startDate <= "2014-05-31" and (endDate >= "2014-05-01" or endDate is NULL)

如何通过按年和月分组来实现这一点?

startDate 应始终为 = firstDayofGivenMonth 或 Null

结果应该是这样的:

year, month, count

2014, 01, 1

2014, 02, 2

2014, 03, 2

2014, 04, 2

2014, 05, 2

2014, 06, 1

...

感谢您的帮助!

史蒂夫

【问题讨论】:

  • (my)sql 中的日期遵循特定格式。除非您掌握了这一点,否则您将一事无成!
  • 我更改了日期格式。日期格式对我来说不是问题。
  • 日期格式绝对是(或曾经是)(至少部分)问题!!
  • 给定月份是什么意思?
  • 你的意思是如果startDate在1月,endDate在3月,那么一月、二月和三月的计数应该加1?

标签: mysql date count group-by where


【解决方案1】:

您需要一个日期范围(年、月)来进行测试。您可以通过不同的方式创建此范围,例如:

SELECT Y, M, DATE_ADD(MAKEDATE(Y, 1), INTERVAL M -1 MONTH) AS FirstDay, LAST_DAY(DATE_ADD(MAKEDATE(Y, 1), INTERVAL M -1 MONTH)) AS LastDay
FROM
  (select 2013 as Y union all select 2014 union all select 2015) years
cross join 
  (select 1 as M 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 union all select 10 union all select 11 union all select 12) months

那么这将是一个简单的连接和分组:

SELECT Y, M, count(d.id)
FROM (
  SELECT Y, M, DATE_ADD(MAKEDATE(Y, 1), INTERVAL M -1 MONTH) AS FirstDay, LAST_DAY(DATE_ADD(MAKEDATE(Y, 1), INTERVAL M -1 MONTH)) AS LastDay
  FROM
   (select 2013 as Y union all select 2014 union all select 2015) years
    cross join 
   (select 1 as M 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 union all select 10 union all select 11 union all select 12) months
) YM
LEFT JOIN dates d ON startDate <= YM.LastDay AND (endDate IS NULL OR endDate >= YM.FirstDay) 
GROUP BY Y, M

【讨论】:

    【解决方案2】:

    我的结果集与你的不符,但是你在寻找这样的东西吗...

    我有一个整数 (0-9) 的实用程序表。我可以用它来构建一个简单的月份日历...

     SELECT '2014-01-01' + INTERVAL i2.i*10+i1.i MONTH dt FROM ints i1,ints i2 HAVING dt < '2015-01-01';
     +------------+
     | dt         |
     +------------+
     | 2014-01-01 |
     | 2014-02-01 |
     | 2014-03-01 |
     | 2014-04-01 |
     | 2014-05-01 |
     | 2014-06-01 |
     | 2014-07-01 |
     | 2014-08-01 |
     | 2014-09-01 |
     | 2014-10-01 |
     | 2014-11-01 |
     | 2014-12-01 |
     +------------+
    

    有了这个,我可以做以下事情......

     DROP TABLE IF EXISTS my_table;
    
     CREATE TABLE my_table
     (id INT NOT NULL AUTO_INCREMENT PRIMARY KEY
     ,startDate DATE NOT NULL
     ,endDate DATE NULL
     );
    
     INSERT INTO my_table VALUES
     (1, '2014-01-01', '2014-02-02'),
     (2, '2014-04-03', NULL),
     (3, '2014-02-02', '2014-05-03');
    
     SELECT DATE_FORMAT(x.dt,'%Y-%m') yearmonth
          , COUNT(y.id) total
       FROM 
          ( SELECT '2014-01-01' + INTERVAL i2.i*10+i1.i MONTH dt FROM ints i1,ints i2 HAVING dt < '2015-01-01' ) x
       LEFT
       JOIN my_table y
         ON DATE_FORMAT(x.dt,'%Y-%m') >= DATE_FORMAT(startdate,'%Y-%m') 
        AND (DATE_FORMAT(x.dt,'%Y-%m') <= DATE_FORMAT(enddate,'%Y-%m') OR y.enddate IS NULL)
      GROUP
         BY yearmonth;
     +-----------+-------+
     | yearmonth | total |
     +-----------+-------+
     | 2014-01   |     1 |
     | 2014-02   |     2 |
     | 2014-03   |     1 |
     | 2014-04   |     2 |
     | 2014-05   |     2 |
     | 2014-06   |     1 |
     | 2014-07   |     1 |
     | 2014-08   |     1 |
     | 2014-09   |     1 |
     | 2014-10   |     1 |
     | 2014-11   |     1 |
     | 2014-12   |     1 |
     +-----------+-------+
    

    【讨论】:

      【解决方案3】:

      首先,创建一个包含您关心的所有月份的表:

      CREATE TABLE months (
          year INTEGER,
          month INTEGER,
          start DATE,
          end DATE,
          PRIMARY KEY (year, month)
      );
      INSERT INTO months VALUES (2014, 1, '2014-01-01', '2014-01-31'), (2014, 2, '2014-02-01', '2014-02-28'), (2014, 3, '2014-03-01', '2014-03-31'), ...;
      

      然后将此表与您的事件表连接起来:

      SELECT m.year, m.month, COUNT(t.id) AS count
      FROM months AS m
      LEFT JOIN YourTable AS t
      ON (startDate BETWEEN m.start AND m.end)
          OR (endDate IS NOT NULL 
              AND m.start BETWEEN startDate AND endDate)
      GROUP BY year, month
      

      我从https://stackoverflow.com/a/14944239/1491895得到了日期范围比较

      DEMO

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-02-03
        • 1970-01-01
        • 2015-11-18
        • 2023-03-28
        • 1970-01-01
        • 1970-01-01
        • 2017-02-15
        • 2014-04-27
        相关资源
        最近更新 更多