Mimo że jest teraz 2017 r., Nadal nie ma konsensusu, czy NULL
powinny one mieć pierwszeństwo. Bez wyrażenia tego wprost, wyniki będą się różnić w zależności od DBMS.
Standard nie określa, jak należy uporządkować wartości NULL w porównaniu z wartościami innymi niż NULL, z wyjątkiem tego, że dowolne dwie wartości NULL należy traktować jako jednakowo uporządkowane, a wartości NULL powinny być sortowane powyżej lub poniżej wszystkich wartości innych niż NULL.
źródło, porównanie większości DBMS
Aby zilustrować problem, stworzyłem listę kilku najpopularniejszych przypadków, jeśli chodzi o rozwój Railsów:
PostgreSQL
NULL
s mają najwyższą wartość.
Domyślnie wartości null są sortowane tak, jakby były większe niż jakakolwiek inna wartość niż null.
źródło: dokumentacja PostgreSQL
MySQL
NULL
s mają najniższą wartość.
Podczas wykonywania ORDER BY, wartości NULL są prezentowane jako pierwsze, jeśli wykonujesz ORDER BY ... ASC, i ostatnie, jeśli wykonujesz ORDER BY ... DESC.
źródło: dokumentacja MySQL
SQLite
NULL
s mają najniższą wartość.
Wiersz z wartością NULL jest wyższy niż wiersze ze zwykłymi wartościami w kolejności rosnącej i jest odwrócony w kolejności malejącej.
źródło
Rozwiązanie
Niestety, same Railsy nie zapewniają jeszcze rozwiązania tego problemu.
Specyficzne dla PostgreSQL
W przypadku PostgreSQL możesz całkiem intuicyjnie użyć:
Photo.order('collection_id DESC NULLS LAST') # NULLs come last
Specyficzne dla MySQL
W przypadku MySQL można umieścić znak minus z góry, ale ta funkcja wydaje się nie być udokumentowana. Wydaje się, że działa nie tylko z wartościami liczbowymi, ale także z datami.
Photo.order('-collection_id DESC') # NULLs come last
Specyficzne dla PostgreSQL i MySQL
Aby objąć oba z nich, wydaje się, że działa to:
Photo.order('collection_id IS NULL, collection_id DESC') # NULLs come last
Mimo to ten nie działa w SQLite.
Uniwersalne rozwiązanie
Aby zapewnić obsługę krzyżową dla wszystkich DBMS, musiałbyś napisać zapytanie przy użyciu CASE
, co sugeruje @PhilIT:
Photo.order('CASE WHEN collection_id IS NULL THEN 1 ELSE 0 END, collection_id')
co przekłada się na pierwsze sortowanie każdego z rekordów najpierw według CASE
wyników (domyślnie rosnąco, co oznacza, że NULL
wartości będą ostatnie), a następnie calculation_id
.