Несмотря на то, что сейчас 2017 год, все еще нет единого мнения о том, должны ли NULL
иметь приоритет.Без вашего явного согласия ваши результаты будут различаться в зависимости от СУБД.
Стандарт не определяет порядок упорядочения значений NULL по сравнению со значениями, отличными от NULL, за исключением того, что любые два значения NULL следует считать одинаково упорядоченными, а значения NULL следует сортировать выше или ниже всех.ненулевые значения.
источник, сравнение большинства СУБД
Чтобы проиллюстрировать проблему, я составил список нескольких наиболее популярных случаев, когда она возникаетдля разработки на Rails:
PostgreSQL
NULL
s имеют самое высокое значение.
По умолчанию нулевые значения сортируются так, как если бы они были больше любого ненулевого значения.
источник: документация PostgreSQL
MySQL
NULL
с имеют самое низкое значение.
При выполнении операции ORDER BY значения NULL отображаются первыми, если вы выполняете ORDER BY ... ASC, и последними, если вы выполняете ORDER BY ... DESC.
источник: документация по MySQL
SQLite
NULL
s имеют наименьшее значение.
Строка сЗначение NULL ha больше, чем строки с обычными значениями в порядке возрастания, и оно инвертировано для порядка убывания.
source
Solution
К сожалению, сам 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
.