(SELECT * FROM tb WHERE start_date < NOW() AND end_date > NOW() ORDER BY end_date ASC)
UNION
(SELECT * FROM tb WHERE start_date > NOW() ORDER BY start_date ASC)
UNION
(SELECT * FROM tb WHERE end_date < NOW() ORDER BY end_date DESC)
для сортировки всего датасета надо добавить поля для неё, приблизительно так
(SELECT *, 1 as f1, UNIX_TIMESTAMP(end_date) as f2 FROM tb WHERE start_date < NOW() AND end_date > NOW() ORDER BY end_date ASC)
UNION
(SELECT * , 2 as f1, UNIX_TIMESTAMP(start_date) as f2 FROM tb WHERE start_date > NOW() ORDER BY start_date ASC)
UNION
(SELECT *, 3 as f1, (UNIX_TIMESTAMP(start_date) - UNIX_TIMESTAMP(end_date)) as f2 FROM tb WHERE end_date < NOW() ORDER BY end_date DESC)
ORDER BY f1, f2 ASC
LIMIT 10,10
но раз вам нужен LIMIT то лучше как то так:
SELECT
*,
if(end_date < NOW(),3,if(start_date > NOW(),2,1)) as f1,
if(end_date < NOW(),UNIX_TIMESTAMP(start_date) - UNIX_TIMESTAMP(end_date),if(start_date > NOW(),UNIX_TIMESTAMP(start_date),UNIX_TIMESTAMP(end_date))) as f2
FROM t1
ORDER BY f1, f2 ASC
LIMIT 10,10
просто этот вариант сложно читаем и вы должны понимать, что в нём и предыдущем индексы для сортировки использоваться не будут никогда