Ответ Джеймса в значительной степени такой, как я бы его кодировал, но в его примере not_as_needed_times не сортируется должным образом, так как вы просили, чтобы элементы с наименьшим количеством времени шли в первую очередь.
Редактировать: Хорошо, этот бегемот позаботится о обо всем :
$sth = $dbh->query("SELECT
(as_needed + morning + afternoon + evening + midnight) AS total_items,
IF((morning + afternoon + evening + midnight) = 0, 0, 1) AS not_as_needed_times,
morning, afternoon, evening, midnight, as_needed
FROM times
WHERE user_id = $user_id
ORDER BY not_as_needed_times DESC, morning DESC, total_items ASC, afternoon DESC, total_items ASC, evening DESC, total_items ASC, midnight DESC, total_items ASC
");
Сначала мы перемещаем not_as_needed_times до конца, затем мы выдвигаем записи, которые имеют morning = 1наверх и упорядочиваем их по количеству выбранных раз, затем мы перемещаем записи с вторником = 1 и так далее.