[英]MySQL Transform a date-range into single rows/count days per year?
我正在寻找一种解决方案,以每年计算一个日期范围内的天数。 我的桌子看起来像这样:
+----+-----------+------------+------------+
| 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和year分组的所有天。
在MySQL中有简单的方法吗?
创建另一个列出所有年份的表:
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
如果您不想创建一个真实的表,可以使用一个子查询来动态创建它:
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
我找到了其他代码片段,并且将两者结合在一起。 它比解决方案更能解决问题,但对于我的目的来说效果很好。
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只是进行迭代的一种解决方法。 不好,但是也许有人需要这样的东西。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.