Несмотря на то, что сейчас 2017 год, до сих пор нет единого мнения о том, NULL
должны ли s иметь приоритет. Если вы не говорите об этом явно, ваши результаты будут зависеть от СУБД.
Стандарт не определяет, как должны быть упорядочены значения NULL по сравнению со значениями, отличными от NULL, за исключением того, что любые два значения NULL должны считаться одинаково упорядоченными и что значения NULL должны сортироваться либо выше, либо ниже всех значений, отличных от NULL.
источник, сравнение большинства СУБД
Чтобы проиллюстрировать проблему, я составил список из нескольких наиболее популярных случаев, когда дело доходит до разработки на Rails:
PostgreSQL
NULL
s имеют наибольшее значение.
По умолчанию значения NULL сортируются так, как если бы они были больше любого ненулевого значения.
источник: документация PostgreSQL
MySQL
NULL
s имеют наименьшее значение.
При выполнении ORDER BY значения NULL отображаются первыми, если вы выполняете ORDER BY ... ASC, и последними, если вы выполняете ORDER BY ... DESC.
источник: документация MySQL
SQLite
NULL
s имеют наименьшее значение.
Строка со значением NULL в порядке возрастания выше, чем строки с обычными значениями, а в порядке убывания она перевёрнута.
источник
Решение
К сожалению, сам Rails пока не предлагает решения для этого.
Специфика PostgreSQL
Для PostgreSQL вы можете довольно интуитивно использовать:
Photo.order('collection_id DESC NULLS LAST') # NULLs come last
Специфичный для MySQL
Для MySQL вы можете поставить знак минус вперед, но эта функция, похоже, недокументирована. Оказывается, работает не только с числовыми значениями, но и с датами.
Photo.order('-collection_id DESC') # NULLs come last
Только для PostgreSQL и MySQL
Чтобы охватить их обоих, это, похоже, работает:
Photo.order('collection_id IS NULL, collection_id DESC') # NULLs come last
Тем не менее, это не работает в SQLite.
Универсальное решение
Чтобы обеспечить кросс-поддержку для всех СУБД, вам нужно будет написать запрос, используя CASE
уже предложенный @PhilIT:
Photo.order('CASE WHEN collection_id IS NULL THEN 1 ELSE 0 END, collection_id')
что переводится как первая сортировка каждой записи сначала по CASE
результатам (по умолчанию в порядке возрастания, что означает, что NULL
значения будут последними), а затем по calculation_id
.