Mysql
MySQL - 合併或拆分日期時間間隔(開始日期到結束日期)
我有一個表,其中儲存了一個活動列表,其中的時間間隔由 2 個日期分隔。
樣本:
+------+---------------------+---------------------+-------------+ | name | start | end | time (calc) | +------+---------------------+---------------------+-------------+ | me | 2017-04-03 11:00:00 | 2017-04-03 11:30:00 | 30 | | me | 2017-04-03 23:45:00 | 2017-04-04 00:15:00 | 30 | | me | 2017-04-04 10:00:00 | 2017-04-04 11:00:00 | 60 | | me | 2017-04-04 10:30:00 | 2017-04-04 11:30:00 | 60 | | me | 2017-04-05 23:00:00 | 2017-04-05 23:30:00 | 30 | | me | 2017-04-05 23:15:00 | 2017-04-07 00:45:00 | 1530 | +------+---------------------+---------------------+-------------+
我想知道每個使用者每天(然後每週)佔用了多少分鐘,所以我需要將目前表轉換為共享部分空間時間的間隔合併為一個,而間隔合併為幾個天是分開的,就像下一個:
+------+---------------------+---------------------+-------------+ | name | start | end | time (calc) | +------+---------------------+---------------------+-------------+ | me | 2017-04-03 11:00:00 | 2017-04-03 11:30:00 | 30 | | me | 2017-04-03 23:45:00 | 2017-04-03 23:59:59 | 15 | | me | 2017-04-04 00:00:00 | 2017-04-04 00:15:00 | 15 | | me | 2017-04-04 10:00:00 | 2017-04-04 11:30:00 | 90 | | me | 2017-04-05 23:00:00 | 2017-04-05 23:59:59 | 60 | | me | 2017-04-06 00:00:00 | 2017-04-06 23:59:59 | 1440 | | me | 2017-04-07 00:00:00 | 2017-04-07 00:45:00 | 45 | +------+---------------------+---------------------+-------------+
然後輕鬆查詢它以獲得每天的分鐘數:
+------+------------+------+ | name | day | time | +------+------------+------+ | me | 2017-04-03 | 45 | | me | 2017-04-04 | 105 | | me | 2017-04-05 | 60 | | me | 2017-04-06 | 1440 | | me | 2017-04-07 | 45 | +------+------------+------+
我正在尋找資訊,我發現如何在這里合並多個日期間隔(mysql - sum interval dates),但是我無法在幾天內分割一個間隔。
可以在單個查詢中完成嗎?我怎麼能做到?
編輯:
SQL(結構和數據):
CREATE TABLE activities ( id INT PRIMARY KEY NOT NULL AUTO_INCREMENT, name VARCHAR(45), start DATETIME, end DATETIME, time INT GENERATED ALWAYS AS (TIMESTAMPDIFF(MINUTE, start, end)) VIRTUAL ); INSERT INTO activities (name, start, end) VALUES ('me','2017-04-03 11:00','2017-04-03 11:30'), ('me','2017-04-03 23:45','2017-04-04 00:15'), ('me','2017-04-04 10:00','2017-04-04 11:00'), ('me','2017-04-04 10:30','2017-04-04 11:30'), ('me','2017-04-05 23:00','2017-04-05 23:30'), ('me','2017-04-05 23:15','2017-04-07 00:45');
SQL合併多個間隔(來源:mysql - sum interval dates):
SELECT name, min(start) AS start, end, TIMESTAMPDIFF(MINUTE, MIN(start), end) AS time FROM ( SELECT x.name, x.start, min(y.end) AS end FROM activities AS x JOIN activities AS y ON x.name = y.name AND x.start <= y.end AND NOT EXISTS ( SELECT 1 FROM activities AS z WHERE y.name = z.name AND y.end >= z.start AND y.end < z.end ) WHERE NOT EXISTS ( SELECT 1 FROM activities AS u WHERE x.name = u.name AND x.start > u.start AND x.start <= u.start ) GROUP BY x.name, x.start ) AS v GROUP BY name, end;
首先,由於您需要生成一系列日期,我建議使用
calendar
表格。CREATE TABLE if not exists calendar ( mdate date PRIMARY KEY NOT NULL ); INSERT INTO calendar values ('20170403'),('20170404'),('20170405'),('20170406'),('20170407'),('20170408');
他們是怎麼做到的呢
只是為了獲得重疊的活動,我使用了您在問題中提供的查詢。
create view overlaped_activities as SELECT name, min(start) AS start, end, TIMESTAMPDIFF(MINUTE, MIN(start), end) AS time FROM ( SELECT x.name, x.start, min(y.end) AS end FROM activities AS x JOIN activities AS y ON x.name = y.name AND x.start <= y.end AND NOT EXISTS ( SELECT 1 FROM activities AS z WHERE y.name = z.name AND y.end >= z.start AND y.end < z.end ) WHERE NOT EXISTS ( SELECT 1 FROM activities AS u WHERE x.name = u.name AND x.start > u.start AND x.start <= u.start ) GROUP BY x.name, x.start ) AS v GROUP BY name, end;
首先,我計算從開始日期到午夜的分鐘數:
if(date(start) = date(end), time_to_sec(timediff(end, start)) / 60, (1440 - time_to_sec(time(start)) / 60)) mstart
然後,如果 start <> end,我計算從午夜到結束日期的分鐘數:
if(date(start) = date(end), 0, time_to_sec(time(end)) / 60) mend
這會返回一個像這樣的表:
| start | end | mdiff | mstart | mend | |---------------------|---------------------|----------:|--------:|--------:| | 03.04.2017 11:00:00 | 03.04.2017 11:30:00 | 30,0000 | 30,0000 | 0 | | 03.04.2017 23:45:00 | 04.04.2017 00:15:00 | 30,0000 | 15,0000 | 15,0000 | | 04.04.2017 10:00:00 | 04.04.2017 11:30:00 | 90,0000 | 90,0000 | 0 | | 05.04.2017 23:00:00 | 07.04.2017 00:45:00 | 1545,0000 | 60,0000 | 45,0000 |
這很好,但這裡還有另一個問題:
| 05.04.2017 23:00:00 | 07.04.2017 00:45:00 | 1545,0000 | 60,0000 | 45,0000 |
當然:
1545 <> 60 + 45
我們需要在開始日期和結束日期之間生成一系列日期,並為每一天添加 1440 分鐘。
我們可以使用日曆表來獲取它:
select name, mdate date_activity, sum(1440) minutes from calendar join overlaped_activities on calendar.mdate > date(start) and calendar.mdate < date(end) where datediff(end, start) > 1 group by name, mdate
好的,我們得到了所有的原料,是時候做菜譜了:
select name, date_activity, sum(minutes) min_activity from ( select name, date(start) date_activity, if(date(start) = date(end), time_to_sec(timediff(end, start)) / 60, (1440 - time_to_sec(time(start)) / 60)) minutes from overlaped_activities UNION ALL select name, date(end) date_activity, if(date(start) = date(end), 0, time_to_sec(time(end)) / 60) minutes from overlaped_activities UNION ALL select name, mdate date_activity, sum(1440) minutes from calendar join overlaped_activities on calendar.mdate > date(start) and calendar.mdate < date(end) where datediff(end, start) > 1 group by name, mdate ) act group by name, date_activity;
最後結果:
| name | date_activity | min_activity | |------|--------------------:|-------------:| | me | 03.04.2017 00:00:00 | 45,0000 | | me | 04.04.2017 00:00:00 | 105,0000 | | me | 05.04.2017 00:00:00 | 60,0000 | | me | 06.04.2017 00:00:00 | 1440,0000 | | me | 07.04.2017 00:00:00 | 45,0000 |
差點忘了,菜譜:http ://rextester.com/EIJOI20983