MySQL Query to Determine Overlapping Timestamps - Schedule System

时间:2016-07-11 19:33:44

标签: php mysql database

I have a table that stores shift records for employees.

Simply, there's the following data:

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)

I am currently determining conflicts through a looping php script but it's far too slow. I've searched other questions and can't quite find the answer I'm looking for.

I am trying to come up with a query that will basically give me a list of employeenums that have conflicting shifts within a given time period.

i.e. for the period 2016-07-03 to 2016-07-10, which employees have overlapping start and end timestamps for shifts with a status value of 1 or 7.

Any help would be appreciated.

Thank you!

EDIT

This is essentially the table structure.

id is a primary auto increment key. The table is full of numeric data.

ID is an autoincremented number, employeenum is a 6 digit number, start and end are unix timetamps, date is YYYY-mm-dd date format, overridden is 1 or 0, status is 1,2,3,4,5,6, or 7.

Current loop works by querying:

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

It then loops through all of those returned shifts to test whether or not another one conflicts with them by executing this query over and over (using the returned start and end values from the results of the above query):

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';"

If there is a result, it pushes the employee number to an array of employees with conflicts. This then prevents the loop from checking for that employee again.

At any given time there could be 10,000 records, so it's executing 10,000+ queries. These records represent only 100-200 employees, so I am looking for a way to query one time to see if there are any overlapping (start and end overlap with another start or end) records between two date values for one employeenum without having to query the database 10,000 times.

2 个答案:

答案 0 :(得分:0)

此查询将为您提供班次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`

答案 1 :(得分:0)

改编自@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`