MySQL将日期范围转换为每年单行/计数天数?

时间:2015-11-04 20:06:36

标签: mysql sql database

我正在寻找一种解决方案来计算每年日期范围内的天数。我的表看起来像这样:

+----+-----------+------------+------------+
| id | source_id | start_date | end_date   |
+----+-----------+------------+------------+
|  1 |         1 | 2015-11-01 | 2017-01-31 |
+----+-----------+------------+------------+

现在我想算上两者之间的日子。它完全容易与DATEDIFF(),但如何每​​年如何做?

我尝试了一种温度。转换为单行以执行计数和组操作:

+----+-----------+------------+------------+
| id | source_id | start_date | end_date   |
+----+-----------+------------+------------+
|  1 |         1 | 2015-11-01 | 2015-12-31 |
+----+-----------+------------+------------+
|  1 |         1 | 2016-01-01 | 2016-12-31 |
+----+-----------+------------+------------+
|  1 |         1 | 2017-01-01 | 2017-01-31 |
+----+-----------+------------+------------+

编辑: 所需的输出应该是这样的:

+-----------+------+------+
| source_id | year | days |
+-----------+------+------+
|         1 | 2015 |   60 |
+-----------+------+------+
|         1 | 2016 |  365 |
+-----------+------+------+
|         1 | 2017 |   30 |
+-----------+------+------+

因此,可以汇总按source_id和年份分组的所有日期。

在MySQL中有一种简单的方法吗?

2 个答案:

答案 0 :(得分:1)

创建另一个列出所有年份的表:

CREATE TABLE years (
    year_start DATE,
    year_end DATE
);
INSERT INTO years VALUES 
    ('2015-01-01', '2015-12-31'), 
    ('2016-01-01', '2016-12-31'),
    ('2017-01-01', '2017-12-31');

然后你可以加入这个表

SELECT t.source_id, YEAR(y.year_start) AS year, DATEDIFF(LEAST(year_end, end_date), GREATEST(year_start, start_date)) AS day_count
FROM yourTable AS t
JOIN years AS y 
    ON y.year_start BETWEEN t.start_date AND t.end_date
    OR y.year_end BETWEEN t.start_date AND t.end_date

DEMO

如果您不想创建真实的表,可以使用创建它的子查询:

SELECT t.source_id, YEAR(y.year_start) AS year, DATEDIFF(LEAST(year_end, end_date), GREATEST(year_start, start_date)) AS day_count
FROM yourTable AS t
JOIN (SELECT CAST('2015-01-01' AS DATE) AS year_start, CAST('2015-12-31' AS DATE) AS year_end
      UNION
      SELECT CAST('2016-01-01' AS DATE) AS year_start, CAST('2016-12-31' AS DATE) AS year_end
      UNION
      SELECT CAST('2017-01-01' AS DATE) AS year_start, CAST('2017-12-31' AS DATE) AS year_end
    ) AS y
    ON y.year_start BETWEEN t.start_date AND t.end_date
    OR y.year_end BETWEEN t.start_date AND t.end_date

DEMO

答案 1 :(得分:0)

我找到了其他一些片段,我将两者结合起来。它更像是一个工作黑客,而不是一个解决方案,但它足以满足我的目的。

SELECT r.source_id, 
   YEAR(y.year_start) AS year,
   DATEDIFF(LEAST(year_end, end_date), GREATEST(year_start, start_date)) AS day_count,
   r.start_date,
   r.end_date
  FROM ranges AS r
  JOIN (
      SELECT @i:= @i + 1 AS YEAR,
             CAST(CONCAT(@i, '-01-01') AS DATE) AS year_start,
             CAST(CONCAT(@i, '-12-31') AS DATE) AS year_end
        FROM INFORMATION_SCHEMA.COLLATION_CHARACTER_SET_APPLICABILITY,
             (SELECT @i:= 1899) AS i
     ) AS y
    ON r.start_date >= y.year_start AND r.start_date <= y.year_end
    OR r.end_date >= y.year_start AND r.end_date <= y.year_end;

我认为,表INFORMATION_SCHEMA.COLLATION_CHARACTER_SET_APPLICABILITY只是进行迭代的一种解决方法。不好,但也许有人需要这样的东西。