Это может быть упрощенная версия того, что вы ищете - она не включает дни, но это должно быть довольно просто добавить:
Пример таблицы с некоторыми данными:
CREATE TABLE `courses` (
`course_id` int(11) NOT NULL AUTO_INCREMENT,
`time_in` time DEFAULT NULL,
`time_out` time DEFAULT NULL,
PRIMARY KEY (`course_id`)
) ENGINE=InnoDB;
INSERT INTO courses VALUES
(1, '09:00', '10:00'),
(2, '09:30', '10:30'),
(3, '10:00', '11:00'),
(4, '10:30', '11:30'),
(5, '12:00', '13:00');
Для каждой строки (каждого временного интервала) определите, есть ли другие строки, которые не перекрываются. Обратите внимание, что это допускает одинаковое время окончания и запуска:
SELECT
c1.course_id,
c1.time_in,
c1.time_out,
c2.course_id,
c2.time_in,
c2.time_out
FROM courses AS c1
JOIN (
SELECT course_id, time_in, time_out FROM courses
) AS c2
ON (c1.time_out > c2.time_in) XOR (c1.time_in < c2.time_out)
ORDER BY c1.course_id, c1.time_in;
+-----------+----------+----------+-----------+----------+----------+
| course_id | time_in | time_out | course_id | time_in | time_out |
+-----------+----------+----------+-----------+----------+----------+
| 1 | 09:00:00 | 10:00:00 | 3 | 10:00:00 | 11:00:00 |
| 1 | 09:00:00 | 10:00:00 | 4 | 10:30:00 | 11:30:00 |
| 1 | 09:00:00 | 10:00:00 | 5 | 12:00:00 | 13:00:00 |
| 2 | 09:30:00 | 10:30:00 | 4 | 10:30:00 | 11:30:00 |
| 2 | 09:30:00 | 10:30:00 | 5 | 12:00:00 | 13:00:00 |
| 3 | 10:00:00 | 11:00:00 | 1 | 09:00:00 | 10:00:00 |
| 3 | 10:00:00 | 11:00:00 | 5 | 12:00:00 | 13:00:00 |
| 4 | 10:30:00 | 11:30:00 | 5 | 12:00:00 | 13:00:00 |
| 4 | 10:30:00 | 11:30:00 | 2 | 09:30:00 | 10:30:00 |
| 4 | 10:30:00 | 11:30:00 | 1 | 09:00:00 | 10:00:00 |
| 5 | 12:00:00 | 13:00:00 | 1 | 09:00:00 | 10:00:00 |
| 5 | 12:00:00 | 13:00:00 | 2 | 09:30:00 | 10:30:00 |
| 5 | 12:00:00 | 13:00:00 | 3 | 10:00:00 | 11:00:00 |
| 5 | 12:00:00 | 13:00:00 | 4 | 10:30:00 | 11:30:00 |
+-----------+----------+----------+-----------+----------+----------+