Mysql 查询以查找访问之间的时间窗口
我正在创建一个小应用程序来注册访问,我一直在寻找访问之间的空闲时间窗口 有两个表,这是一个简化的结构: 工作时间 -开始时间 -结束时间 拜访 -开始时间 -结束时间 -探访 值为2的访问状态为取消访问,因此我们不包括这些访问 现在举个小例子: 员工有自己的工作时间,包括休息时间,例如:Mysql 查询以查找访问之间的时间窗口,mysql,sql,database,Mysql,Sql,Database,我正在创建一个小应用程序来注册访问,我一直在寻找访问之间的空闲时间窗口 有两个表,这是一个简化的结构: 工作时间 -开始时间 -结束时间 拜访 -开始时间 -结束时间 -探访 值为2的访问状态为取消访问,因此我们不包括这些访问 现在举个小例子: 员工有自己的工作时间,包括休息时间,例如: | start_time | end_time | | 2018-12-29 08:00:00 | 2018-12-29 12:00:00 | | 2018-12-29
| 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
这看起来不像是一个简单的缺口和孤岛问题 首先有一个问题,就是要找出访问之间的差距是否足够大。 这意味着需要同时考虑开始和结束时间 然后,当发现这些间隙时,它们需要在30分钟的间隔内展开 要展开间隙,可以链接到数字表。 最好创建一个永久的。 下面的示例只是添加了一些值,以使这个答案保持简单。 但还有其他方法。F.e。 这样的查询将在MySql 5.7中工作
您可以在dbfiddle上测试它此查询不包括14:00、14:30、15:00等小时数。这仍然是预订30分钟的正确时间visit@kamcik现在它找到了缺口,就像一个符咒!非常感谢。我应该改变什么来找出40分钟访问或任何其他时间间隔的间隔?查看HAVING中的第二个标准并了解它的作用。关于时间间隔的展开,看看num是在哪里使用的。因为它是每个员工的,我们可以假设在工作时间里有类似emp_id的东西吗?那么在访问中也是这样吗?你基本上是在寻找访问中的差距?属性emp_id不相关,我们可以假设有一名员工。正如我在描述中提到的,我希望在已预订的访问之间为新访问找到30分钟的时间窗口。有一次访问在14:00:00结束,另一次预订的访问在15:30开始,所以我可以在3个不同的时间预订一次新的访问-14:00,14:30,15:00。@Kamcik。为什么你不能在14:15或14:50预订?浪费时间-在14:00和15:30之间,你可以预订三次30分钟的访问,当你在14:15预订访问时,你在14:00和14:15之间浪费时间,你只能预订两次访问14:15和14:45,这都是因为下一个时间窗口是15:15,没有时间进行30分钟的访问。
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);
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;
start_time
08:30:00
10:40:00
14:00:00
14:30:00
15:00:00