SQL как сделать нулевые значения последними при сортировке по возрастанию

297

У меня есть таблица SQL с полем datetime. Поле, о котором идет речь, может быть нулевым. У меня есть запрос, и я хочу, чтобы результаты сортировались по возрастанию по полю datetime, однако я хочу строки, в которых поле datetime равно нулю в конце списка, а не в начале.

Есть ли простой способ сделать это?

Давид Божьяк
источник
5
Точная копия stackoverflow.com/questions/151195/…
Билл Карвин

Ответы:

394
select MyDate
from MyTable
order by case when MyDate is null then 1 else 0 end, MyDate
RedFilter
источник
2
Однако обратите внимание, что если вы поместите индекс в столбец сортировки для повышения производительности (*), то этот метод несколько усложнит план запроса и потеряет большую часть выигрыша в производительности. * - индексы предоставили предварительно отсортированные данные, что позволило избежать сортировки при выполнении запроса. Желательно отфильтровать записи NULL, если это возможно, чтобы полностью избежать этой проблемы.
Redcalx
2
Хороший ответ также дан здесь со всеми возможными способами с преимуществами и недостатками nickstips.wordpress.com/2010/09/30/…
sudhAnsu63
40
order by case when MyDate is null then 1 else 0 endэто очень длинный способ сказатьORDER BY MyDate IS NULL
Мартин
5
@Martin Обратите внимание, что этот вопрос не помечен MySQL. Я предоставил обобщенное решение - есть много разных способов сделать одно и то же на разных БД.
RedFilter
1
@KyleDelaney Потому что order by 0интерпретируется как индекс столбца, а индексы столбца основаны на 1. Чтобы отсортировать запрос по 3-му столбцу, можно сказать order by 3(что является ужасной идеей для рабочих запросов), но очень удобно (как есть *) при экспериментах.
RedFilter
159

(«Немного» поздно, но об этом вообще не упоминалось)

Вы не указали свою СУБД.

В стандартном SQL (и в большинстве современных СУБД, таких как Oracle, PostgreSQL, DB2, Firebird, Apache Derby, HSQLDB и H2) вы можете указать NULLS LASTили NULLS FIRST:

Используйте, NULLS LASTчтобы отсортировать их до конца:

select *
from some_table
order by some_column DESC NULLS LAST
a_horse_with_no_name
источник
16
AFAIK NULLS FIRSTи NULLS LASTбыли добавлены в SQL: 2003, но в разных DMBS нет стандартной реализации. В зависимости от механизма базы данных используйте ORDER BY expr some_column DESC NULLS LAST(Oracle), ORDER BY ISNULL(some_column, 1), some_column ASC(MSSQL) или ORDER BY ISNULL(some_column), some_column ASC(MySQL с другой реализацией ISNULL ()).
SaschaM78
3
@ SaschaM78: сортировка по умолчанию NULL зависит от СУБД. Некоторые сортируют их в конце, некоторые в начале. Некоторые не заботятся о ASC/ DESCс нулями, некоторые делают. Таким образом, единственный способ обеспечить это - использовать, NULL FIRST/LAST если СУБД поддерживает это. У него документы, что вы намерены. Использование isnull()или других функций - это обходной путь для отсутствующей поддержки NULLS FIRST/LAST(которая поддерживается Oracle, PostgreSQL, DB2, Firebird, Apache Derby, HSQLDB и H2)
a_horse_with_no_name
Вы совершенно правы, я просто хотел добавить тот факт, что есть довольно много СУБД, которые не соответствуют стандарту (пока) или имеют свои особенности, такие как Oracle, требующие exprключевое слово при использовании NULLS FIRST / LAST. И спасибо за то, что значения null показываются первыми / последними в зависимости от типа базы данных, не знал этого!
SaschaM78
2
Это выглядит многообещающе, но, к сожалению, я попробовал и NULLS LASTне работал в моей базе данных MySQL.
AdmiralThrawn
1
@AdmiralAdama: вы всегда можете перейти на Postgres
a_horse_with_no_name
35

Я также наткнулся на это, и следующее, похоже, помогает мне в MySQL и PostgreSQL:

ORDER BY date IS NULL, date DESC

как найдено на https://stackoverflow.com/a/7055259/496209

Luksurious
источник
Это выглядит многообещающе, но , к сожалению, я попробовал и IS NULLи IS NOT NULLне сделал работу в моей базе данных MySQL.
AdmiralThrawn
14
order by coalesce(date-time-field,large date in future)
Gratzy
источник
10
Хотя в целом это будет работать, следует отметить, что у этого ответа есть несколько проблем: большая дата в будущем может столкнуться с фактическими данными или будет меньше их, что приведет к несовершенной сортировке. Кроме того, это решение «магического числа», которое не является самодокументированным.
RedFilter
Это хорошая альтернатива ответу @RedFilter, когда вам нужно сравнить рассматриваемый столбец с другим столбцом даты. Я использую это для профсоюзного списка старшинства. Если у сотрудника есть Квалифицированная дата (которая может быть обнуляемой), эта дата всплывет на вершине, в противном случае используйте HireDate. Использование ORDER BY ISNULL (QualifiedDate, '1-1-2099'), HireDate, LastName и т. Д. Делает квалифицированную дату не конфликтующей с датой HiredDate и создает правильный список старости.
Алан Фишер
14

Вы можете использовать встроенную функцию для проверки на ноль или не ноль, как показано ниже. Я проверяю его и он работает нормально.

select MyDate from MyTable order by ISNULL(MyDate,1) DESC, MyDate ASC;

Маджди М. Абурахела
источник
Для дат, чтобы работать с mssql, я нашел полезным поместить далеко в будущую дату в функцию ISNULL, т.е. ISNULL (MyDate, '2100-01-01')
Emi-C
В MySQL написано, что я передаю слишком много параметров. Я получил это, чтобы разобрать, делая ISNULL(MyDate) DESC, MyDate ASC, но это не сортировать в правильном порядке.
AdmiralThrawn
12

Если ваш двигатель позволяет ORDER BY x IS NULL, xили ORDER BY x NULLS LASTиспользовать это. Но если это не так, это может помочь:

Если вы сортируете по числовому типу, вы можете сделать это: (Заимствование схемы из другого ответа .)

SELECT *          
FROM Employees
ORDER BY ISNULL(DepartmentId*0,1), DepartmentId;

результат показ отсортирован по DepartmentId с нулями последний

Любое ненулевое число становится 0, а нули становятся 1, что означает, что сортировка нуля выполняется в последнюю очередь.

Вы также можете сделать это для строк:

SELECT *
FROM Employees
ORDER BY ISNULL(LEFT(LastName,0),'a'), LastName

результат показ отсортирован по LastName с нулями last

Потому что 'a'> ''.

Это даже работает с датами, приводя к обнуляемому int и используя метод для целых чисел выше:

SELECT *
FROM Employees
ORDER BY ISNULL(CONVERT(INT, HireDate)*0, 1), HireDate

(Давайте представим, что схема имеет HireDate.)

Эти методы позволяют избежать необходимости придумывать или управлять «максимальным» значением каждого типа или исправлять запросы, если тип данных (и максимальный) изменяется (обе проблемы, с которыми сталкиваются другие решения ISNULL). Плюс они намного короче чем ДЕЛО.

infogulch
источник
Прекрасно работает ! Спасибо
Вани
8

Когда ваш столбец заказа числовой (например, ранг), вы можете умножить его на -1, а затем заказать по убыванию. Это сохранит порядок, который вы ожидаете, но поставьте NULL последним.

select *
from table
order by -rank desc
Luizgrs
источник
Был только что прокомментировать это. Узнал об этом от stackoverflow.com/a/8174026/1193304 и это здорово
Крис
3

Спасибо RedFilter за отличное решение проблемы с ошибками сортировки поля datetime.

Я использую базу данных SQL Server для своего проекта.

Изменение нулевого значения datetime на '1' решает проблему сортировки для столбца типа данных datetime. Однако если у нас есть столбец с типом данных, отличным от datetime, он не может быть обработан.

Чтобы обработать сортировку столбцов varchar, я попытался использовать 'ZZZZZZZ', так как знал, что столбец не имеет значений, начинающихся с 'Z'. Это сработало, как и ожидалось.

В тех же строках я использовал максимальные значения +1 для int и других типов данных, чтобы получить сортировку, как и ожидалось. Это также дало мне результаты, которые были необходимы.

Тем не менее, всегда было бы идеально получить что-то более простое в самом движке базы данных, которое могло бы сделать что-то вроде:

Order by Col1 Asc Nulls Last, Col2 Asc Nulls First 

Как указано в ответе, предоставленном a_horse_with_no_name.

Касим Хусаини
источник
3

В Oracle вы можете использовать NULLS FIRSTили NULLS LAST: указывает, что значения NULL должны возвращаться до / после значений, отличных от NULL:

ORDER BY { column-Name | [ ASC | DESC ] | [ NULLS FIRST | NULLS LAST ] }

Например:

ORDER BY date DESC NULLS LAST

Ссылка: http://docs.oracle.com/javadb/10.8.3.0/ref/rrefsqlj13658.html

Joaquinglezsantos
источник
3

Если вы используете MariaDB, они упоминают следующее в документации NULL Values .

заказ

Когда вы упорядочиваете поле, которое может содержать значения NULL, любые значения NULL считаются самыми низкими. Таким образом, при заказе в порядке DESC NULL будут появляться последними. Чтобы заставить NULL считаться самыми высокими значениями, можно добавить еще один столбец, который имеет более высокое значение, когда основным полем является NULL. Пример:

SELECT col1 FROM tab ORDER BY ISNULL(col1), col1;

По убыванию, с NULL в первую очередь:

SELECT col1 FROM tab ORDER BY IF(col1 IS NULL, 0, 1), col1 DESC;

Все значения NULL также считаются эквивалентными для целей предложений DISTINCT и GROUP BY.

Выше показаны два способа упорядочения по значениям NULL, вы также можете комбинировать их с ключевыми словами ASC и DESC. Например, другой способ сначала получить значения NULL:

SELECT col1 FROM tab ORDER BY ISNULL(col1) DESC, col1;
--                                         ^^^^
3limin4t0r
источник
2

Решение с использованием «case» является универсальным, но тогда не используйте индексы.

order by case when MyDate is null then 1 else 0 end, MyDate

В моем случае мне нужна производительность.

 SELECT smoneCol1,someCol2  
 FROM someSch.someTab
 WHERE someCol2 = 2101 and ( someCol1 IS NULL ) 
  UNION   
 SELECT smoneCol1,someCol2
 FROM someSch.someTab
 WHERE someCol2 = 2101 and (  someCol1 IS NOT NULL)  
Adam111p
источник
1
Если вы заинтересованы в производительности, вы должны использовать UNION ALL.
RedFilter
0
order by -cast([nativeDateModify] as bigint) desc
папараццо
источник