SQL як зробити нульові значення останніми при сортуванні за зростанням


297

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

Чи є простий спосіб досягти цього?



Відповіді:


394
select MyDate
from MyTable
order by case when MyDate is null then 1 else 0 end, MyDate

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. Я запропонував узагальнене рішення - існує багато різних способів зробити одну й ту саму річ у різних dbs.
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

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. І дякую, що нульові показані першими / останніми різняться від типу бази даних до типу, не знав цього!
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


Це виглядає багатообіцяюче, але , до жаль, я спробував і IS NULLі IS NOT NULLне зробив роботу в моїй базі даних MySQL.
AdmiralThrawn

14
order by coalesce(date-time-field,large date in future)

10
Хоча це, як правило, спрацює, слід зазначити, що ця відповідь має кілька питань: велика дата в майбутньому може зіткнутися з фактичними даними або бути меншою, що призведе до недосконалого сортування. Крім того, це рішення "магічного числа", яке не є самодокументуванням.
RedFilter

Це може бути чудовою альтернативою відповіді @RedFilter, коли вам потрібно порівняти відповідний стовпець з іншим стовпцем дати. Я використовую це для списку стажу профспілки. Якщо у працівника є кваліфікована дата (яка є нульовою), ці дати бульбашки записують доверху, інакше використовуйте HireDate. Використовуючи ЗАМОВЛЕННЯ ISNULL (QualifiedDate, '1-1-2099'), HireDate, LastName та ін. Робить дату Кваліфікованої суперечності з датою HiredDate, і створюється правильний список старійності.
Алан Фішер

14

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

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 з останніми нулями

Тому що 'a'> ''.

Це навіть працює з датами, примушуючи до нульового int та використовуючи метод для ints вище:

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

(Нехай робить вигляд, що схема має HireDate.)

За допомогою цих методів уникнути питання щодо необхідності створення або максимального керування значенням кожного типу або виправлення запитів, якщо тип даних (і максимум) змінюється (обидва питання, від яких страждають інші рішення ISNULL). Плюс вони набагато коротші, ніж СПРАВКА.


Чудово працює! Дякую
Вані

8

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

select *
from table
order by -rank desc

Якраз збирався прокоментувати це. Дізнався це з stackoverflow.com/a/8174026/1193304, і це чудово
Кріс,


3

Дякуємо RedFilter за прекрасне вирішення проблеми помилок сортування зведеного поля часу.

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

Зміна нульового значення datetime на '1' вирішує проблему сортування за стовпцем типу datatime datetime. Однак якщо у нас стовпець, який не є типом даних datetime, він не справляється.

Для обробки сортування колонок varchar я спробував використовувати "ZZZZZZZ", оскільки я знав, що стовпець не має значень, починаючи з "Z". Це спрацювало як очікувалося.

У тих же рядках я використовував максимальні значення +1 для int та інших типів даних, щоб отримати сортування, як очікувалося. Це також дало мені необхідні результати.

Однак завжди було б ідеально отримати щось простіше в самому двигуні бази даних, що може зробити щось на кшталт:

Order by Col1 Asc Nulls Last, Col2 Asc Nulls First 

Як зазначено у відповіді, наданій a_horse_with_no_name.



3

Якщо ви використовуєте MariaDB, вони згадують наступне в документації про значення NULL .

Замовлення

Коли ви замовляєте поле, яке може містити значення 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;
--                                         ^^^^

2

Рішення за допомогою "справи" є універсальним, але тоді не використовуйте індекси.

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)  

1
Якщо ви зацікавлені в продуктивності, яку ви повинні використовувати UNION ALL.
RedFilter


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.