我正在创建一个用于注册访问的小应用程序,但我一直坚持寻找访问之间的空闲时间窗口。
有两个表,这是一个简化的结构:
working_hours
-开始时间
-end_time
访问
-开始时间
-结束时间
-visit_status
值为“ 2”的visits_status被取消了访问,因此我们不包括这些访问
现在是一个小例子:
员工有自己的工作时间,其中包括休息时间,例如:
| start_time | end_time |
| 2018-12-29 08:00:00 | 2018-12-29 12:00:00 |
| 2018-12-29 12:30:00 | 2018-12-29 16:00:00 |
已经在应用中注册了访问,它们的持续时间可能有所不同。参观时间已包括在内,因此下次参观可以在之后开始。假设我们有类似的访问:
| start_time | end_time | visit_status |
| 2018-12-29 08:00:00 | 2018-12-29 08:30:00 | 1 |
| 2018-12-29 09:00:00 | 2018-12-29 10:00:00 | 1 |
| 2018-12-29 10:00:00 | 2018-12-29 10:40:00 | 1 |
| 2018-12-29 10:40:00 | 2018-12-29 11:10:00 | 2 |
| 2018-12-29 11:10:00 | 2018-12-29 11:40:00 | 0 |
| 2018-12-29 12:30:00 | 2018-12-29 13:00:00 | 0 |
| 2018-12-29 13:00:00 | 2018-12-29 14:00:00 | 0 |
| 2018-12-29 15:30:00 | 2018-12-29 16:00:00 | 0 |
我的目标是创建一个查询,该查询将向我显示30分钟的可用开始时间,包括工作时间,在这种情况下,结果应为以下时间:
- 8:30
- 10:40
- 14:00
- 14:30
- 15:00
答案 0 :(得分:0)
这看起来不像是一个直接的差距与孤岛问题。
首先是要找到足够大的访问之间的差距。
这意味着开始时间和结束时间都需要考虑。
然后,当发现这些间隙时,需要以30分钟为间隔展开。
要展开差距,您可以链接到数字表。
最好创建一个永久的。
下面的示例仅添加值,以使此答案变得简单。
但是还有其他方法。 F.e. here
create table nums (num int primary key not null);
insert into nums (num) VALUES
(00),(01),(02),(03),(04),(05),(06),(07),(08),(09),
(10),(11),(12),(13),(14),(15),(16),(17),(18),(19),
(20),(21),(22),(23),(24),(25),(26),(27),(28),(29),
(30),(31),(32),(33),(34),(35),(36),(37),(38),(39),
(40),(41),(42),(43),(44),(45),(46),(47),(48),(49);
然后这样的查询将在MySql 5.7中工作
SELECT DISTINCT
CAST(gaps.start_dt + INTERVAL (nums.num * 30) MINUTE AS TIME) as start_time
FROM
(
SELECT rnk, MIN(prev_dt) as start_dt, MIN(start_dt) as end_dt
FROM
(
SELECT
start_time AS start_dt,
end_time as end_dt,
@prev_dt as prev_dt,
-- DATE(@prev_dt) + INTERVAL (CEIL(TIME_TO_SEC(@prev_dt) / 600) * 600) SECOND as prev_dt,
(CASE
WHEN @prev_dt = start_time AND @prev_dt := end_time THEN @rnk
WHEN @prev_dt := end_time THEN @rnk := @rnk + 1
END) AS rnk
FROM visits
CROSS JOIN (SELECT @prev_dt := null, @rnk := 0) vars
WHERE visit_status <> 2
ORDER BY start_time
) AS vst
GROUP BY rnk
HAVING CAST(MIN(start_dt) AS DATE) = CAST(MIN(prev_dt) AS DATE)
AND TIMEDIFF(MIN(start_dt), MIN(prev_dt)) >= CAST('00:30' AS TIME)
) gaps
JOIN working_hours wrk
ON wrk.start_time <= gaps.start_dt AND wrk.end_time >= gaps.end_dt
JOIN nums
ON nums.num BETWEEN 0 AND 47
AND gaps.start_dt + INTERVAL (nums.num * 30) MINUTE < gaps.end_dt;
“ vst”子查询通过使用变量为日期时间分配排名。
然后,“差距”子查询按排名对它们进行分组,以找到差距的开始和结束。
然后加入Working_hours。
“数字”表用于以30分钟为间隔显示时间。
结果:
start_time
08:30:00
10:40:00
14:00:00
14:30:00
15:00:00
您可以在 db <>小提琴here
上对其进行测试