【问题标题】:MySQL Query to Determine Overlapping Timestamps - Schedule SystemMySQL 查询以确定重叠时间戳 - 调度系统
【发布时间】:2016-07-15 03:18:46
【问题描述】:

我有一个存储员工轮班记录的表。

简单来说就是以下数据:

id = Shift ID
employeenum = Employee Number
start = unix timestamp of shift start time
end = unix timestamp of shift end time
date = YYYY-mm-dd description of date the shift starts on
status = shift status (numeric status identifier)

我目前正在通过循环 php 脚本确定冲突,但它太慢了。我搜索了其他问题,但找不到我正在寻找的答案。

我正在尝试提出一个查询,该查询基本上会给我一个在给定时间段内具有冲突轮班的员工编号列表。

即在 2016 年 7 月 3 日至 2016 年 7 月 10 日期间,哪些员工的轮班开始和结束时间戳重叠,状态值为 1 或 7。

任何帮助将不胜感激。

谢谢!

编辑

This本质上是表结构。

id 是一个主要的自动增量键。该表充满了数字数据。

ID 是一个自动递增的数字,employeenum 是一个 6 位数字,开始和结束是 unix 时间戳,日期是 YYYY-mm-dd 日期格式,覆盖是 1 或 0,状态是 1,2,3,4,5 ,6 或 7。

当前循环通过查询来工作:

SELECT *  FROM schedule WHERE overridden =0 AND date >=$startdate AND date <= $enddate AND (status = 1 OR status = 7)  AND employeenum != 0 ORDER BY date ASC

然后循环遍历所有返回的班次,通过反复执行此查询(使用上述查询结果中返回的start 和end 值)来测试另一个班次是否与它们发生冲突:

SELECT `employeenum` FROM `schedule` WHERE `overridden` =0 AND `date` >= '$startdate' AND `date` <= '$enddate' AND (`status` = '1' OR `status` = '7') AND ((('$start' > `start`) AND ('$start' < `end`)) OR ((`end` > '$start') AND (`end` < '$end'))) AND `employeenum` = '$employee';"

如果有结果,它将员工编号推送到有冲突的员工数组中。这样可以防止循环再次检查该员工。

在任何给定时间都可能有 10,000 条记录,因此它正在执行 10,000 多个查询。这些记录仅代表 100-200 名员工,因此我正在寻找一种方法来查询一次以查看两个 @ 之间是否有任何重叠(start 和 end 与另一个 start 或 end 重叠)记录一个 employeenum 的 987654332@ 值,而无需查询数据库 10,000 次。

【问题讨论】:

  • 让我们看看你的 php 代码!
  • 基本上它遵循这个逻辑:选择时间段内的记录。循环遍历记录,如果员工编号不在冲突数组中,则检查是否存在冲突。如果存在冲突,将员工编号推送到冲突数组。移至下一条记录。问题是它太慢了,而且每次都一遍又一遍地查询。如果可能的话,我想用一个查询来解决这个问题。
  • 抱歉,这里的解释不会删减,请附上您的代码,我们可以提供帮助
  • 谢谢你,我很感激你的意图,但是正如我所说,我正在寻找一个查询解决方案,而不是对 PHP 代码的修订。客户端使用的托管包无法进行迭代重复查询,这就是为什么我试图通过每个员工 1 个查询来完成它。我正在寻求构建查询的帮助。
  • 好的,你需要包含你的原始查询,你还应该更新你的数据结构,即id你的主自动增量键 - 或者 - 它是链接到班次的外键表...在此处提供一些示例数据或粘贴内容sqlfiddle.com 并提供链接

标签: php mysql database


【解决方案1】:

此查询将为您提供班次 ID、日期、员工编号、冲突的员工编号和冲突班次的计数。您的数据集中有大量发生冲突的转变!!!

SELECT `schedule_test`.`id`, `schedule_test`.`date`, `schedule_test`.`employeenum`, GROUP_CONCAT(DISTINCT`join_tbl`.`employeenum`), COUNT(`join_tbl`.`employeenum`)
FROM `schedule_test` 
INNER JOIN `schedule_test` AS `join_tbl` ON 
    `schedule_test`.`date` = `join_tbl`.`date` 
    AND (`join_tbl`.`status` = 1 OR `join_tbl`.`status` = 7) 
    AND (`join_tbl`.`start` BETWEEN `schedule_test`.`start` AND `schedule_test`.`end` 
        OR `join_tbl`.`end` BETWEEN `schedule_test`.`start` AND `schedule_test`.`end`) 
    AND `schedule_test`.`id` != `join_tbl`.`id` 
WHERE (`schedule_test`.`status` = 1 OR `schedule_test`.`status` = 7) 
GROUP BY `schedule_test`.`id`
ORDER BY `schedule_test`.`date`

【讨论】:

  • 嗯非常接近,但它返回数据集中的所有员工编号,无论它们是否冲突。我在这里包含了一个更大的数据集(最大的 sqlfiddle 将允许我这样做)。不过我喜欢这个方向,很有创意。 sqlfiddle.com/#!9/788762
  • @benp 它工作正常,你只有那么多班次重叠,如果你有一个班次重叠 27 个人,你就有 27 次冲突。你会得到他们每个人的名单。我已更新我的答案以提供更多详细信息。
  • 对不起,我认为您误解了我认为的冲突。如果员工 A 在同一时间安排了两次,那就是冲突。如果同时安排员工 A 和 B,这不是冲突。但是,很容易修复。非常感谢您的帮助,如果没有您的帮助,我不会想到这一点。
【解决方案2】:

改编自@cmorrissey 的回答。谢谢!!

SELECT `schedule_test`.`id`, `schedule_test`.`date`, 
`schedule_test`.`employeenum`,     
GROUP_CONCAT(DISTINCT`join_tbl`.`employeenum`),  
COUNT(`join_tbl`.`employeenum`)

FROM `schedule_test` 
INNER JOIN `schedule_test` AS `join_tbl` ON 
`schedule_test`.`date` = `join_tbl`.`date` 
AND (`join_tbl`.`status` = 1 OR `join_tbl`.`status` = 7)
AND (`join_tbl`.`employeenum` = `schedule_test`.`employeenum`) 
AND (`join_tbl`.`start` BETWEEN `schedule_test`.`start` AND `schedule_test`.`end` 
    OR `join_tbl`.`end` BETWEEN `schedule_test`.`start` AND `schedule_test`.`end`) 
AND `schedule_test`.`id` != `join_tbl`.`id` 
WHERE (`schedule_test`.`status` = 1 OR `schedule_test`.`status` = 7) 
GROUP BY `schedule_test`.`id`
ORDER BY `schedule_test`.`date`

【讨论】:

    猜你喜欢
    • 2013-01-07
    • 1970-01-01
    • 2023-01-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-16
    • 2021-04-07
    • 2018-12-29
    相关资源
    最近更新 更多