benp benp - 3 months ago 11
MySQL Question

MySQL Query to Determine Overlapping Timestamps - Schedule System

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!


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
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 (
overlap with another
) records between two
values for one
without having to query the database 10,000 times.


Adapted from @cmorrissey 's answer. THANK YOU!!

SELECT `schedule_test`.`id`, `schedule_test`.`date`, 

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`