Незважаючи на те, що зараз 2017 рік, все ще не було досягнуто консенсусу щодо того, чи NULL
слід мати пріоритет. Без того, що ви чітко про це заявляєте, ваші результати будуть змінюватися залежно від СУБД.
Стандарт не визначає, як слід упорядковувати NULL у порівнянні зі значеннями, що не є NULL, за винятком того, що будь-які два NULL слід вважати однаково упорядкованими, і що NULL повинні сортувати або вище, або нижче всіх значень, що не є NULL.
джерело, порівняння більшості СУБД
Щоб проілюструвати проблему, я склав список кількох найпопулярніших випадків, коли мова йде про розробку Rails:
PostgreSQL
NULL
s мають найвище значення.
За замовчуванням нульові значення сортуються так, ніби більші за будь-які ненульові значення.
джерело: документація 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
.