按年,月份分组,具有2个日期字段条件

时间:2014-11-20 09:48:15

标签: mysql date count group-by where

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

我有一个包含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应始终为&lt; = lastDayofGivenMonth和endDate&gt; = firstDayofGivenMonth或Null

结果应如下所示:

year, month, count

2014, 01, 1

2014, 02, 2

2014, 03, 2

2014, 04, 2

2014, 05, 2

2014, 06, 1

...

感谢您的帮助!

史蒂夫

3 个答案:

答案 0 :(得分:0)

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

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

答案 1 :(得分:0)

我的结果集与你的结果不符,但你是否正在寻找类似的东西...

我有一个整数的实用程序表(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 |
 +-----------+-------+

答案 2 :(得分:0)

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

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