SQL Server ЗАМОВИТИ ЗА ДАТАМИ та нулями останніми


82

Я намагаюся замовити за датою. Я хочу, щоб найновіші дати були першими. Це досить просто, але є багато записів, які є нульовими, і вони з’являються перед будь-якими записами, які мають дату.

Я спробував кілька речей без успіху:

ORDER BY ISNULL(Next_Contact_Date, 0)

ORDER BY ISNULL(Next_Contact_Date, 999999999)

ORDER BY coalesce(Next_Contact_Date, 99/99/9999)

Як я можу впорядкувати за датою, і щоб нулі прийшли останніми? Тип даних - smalldatetime.


Чи порядок сортування має бути зростаючим, але з нулями в кінці? І чи буде у вас в таблиці майбутні дати?
AllenG

@AllenG, так, з минулого в майбутнє з минулим першим і так далі. Так так, за зростанням. Так, більшість із них будуть майбутніми датами.
UpHelix

Відповіді:


112

smalldatetime має діапазон до 6 червня 2079 р., щоб ти міг використовувати

ORDER BY ISNULL(Next_Contact_Date, '2079-06-05T23:59:00')

Якщо жоден законний запис не матиме цієї дати.

Якщо це не припущення, ви, мабуть, покладаєтесь на більш надійний варіант, сортуєте за двома стовпцями.

ORDER BY CASE WHEN Next_Contact_Date IS NULL THEN 1 ELSE 0 END, Next_Contact_Date

Обидві наведені вище пропозиції не можуть використовувати індекс, щоб уникнути сортування та надати схожі плани.

введіть тут опис зображення

Інша можливість існування такого індексу є

SELECT 1 AS Grp, Next_Contact_Date 
FROM T 
WHERE Next_Contact_Date IS NOT NULL
UNION ALL
SELECT 2 AS Grp, Next_Contact_Date 
FROM T 
WHERE Next_Contact_Date IS NULL
ORDER BY Grp, Next_Contact_Date

План


Цей фокус можна застосувати і до VARCHARполів (наприклад ORDER BY ISNULL(my_varchar, 'ZZZZZZ')) і надзвичайно корисний, особливо для отримання замовлень певним чином при використанні GROUP BY . . . GROUPING SETS. Дякуємо, що розмістили це.
sparc_spread

Чому ми не можемо використовувати порядок за desc, щоб розмістити нулі внизу? також, чому ми відображаємо нуль до 1?
MasterJoe

35

За словами Іціка Бен-Гана, автора " Основ T-SQL для MS SQL Server 2012" , "За замовчуванням SQL Server сортує NULL позначки перед не NULL значеннями. Щоб отримати NULL позначки для сортування останніми, ви можете використовувати вираз CASE, який повертає 1, коли стовпець " Next_Contact_Date має значення NULL ", і 0, якщо це не NULL . Незнаки NULL отримують 0 з виразу; тому вони сортуються перед позначками NULL (які отримують 1). Цей вираз CASE використовується як перший сортувати стовпець ". Next_Contact_Dateстовпець "повинен бути вказаний як другий стовпець сортування. Таким чином, не- NULL позначки правильно сортують між собою" Ось запит рішення для вашого прикладу для MS SQL Server 2012 (та SQL Server 2014):

ORDER BY 
   CASE 
        WHEN Next_Contact_Date IS NULL THEN 1
        ELSE 0
   END, Next_Contact_Date;

Еквівалентний код із використанням синтаксису IIF:

ORDER BY 
   IIF(Next_Contact_Date IS NULL, 1, 0),
   Next_Contact_Date;

Крім того, щоб додати до відповіді, якщо ви переключите значення IIF 1 і 0 навколо нулів, це перейде до початку. Це також працює, якщо ви хочете виділити кортежі, поставивши їх у верхній частині таблиці.
Франко Петтігроссо

3

Якщо ваш SQL не підтримує NULLS FIRSTабо NULLS LAST, найпростіший спосіб зробити це - використовувати value IS NULLвираз:

ORDER BY Next_Contact_Date IS NULL, Next_Contact_Date

поставити нулі в кінці ( NULLS LAST) або

ORDER BY Next_Contact_Date IS NOT NULL, Next_Contact_Date

поставити нулі спереду. Це не вимагає знання типу стовпця і легше для читання, ніж CASEвираз.

EDIT: На жаль, хоча це працює в інших реалізаціях SQL, таких як PostgreSQL та MySQL, в MS SQL Server це не працює. У мене не було SQL Server для тестування, я покладався на документацію Microsoft та тестування з іншими реалізаціями SQL. На думку Microsoft, value IS NULL це вираз, який повинен бути використаний, як і будь-який інший вираз. І ORDER BY має приймати вирази, як і будь-яке інше твердження, яке приймає вираз. Але це насправді не працює.

Тому найкращим рішенням для SQL Server є CASEвираз.


7
Це невірний синтаксис SQL Server
Мартін Сміт

3
Вибач за це. Він повинен бути дійсним відповідно до документації Microsoft і працює в інших SQL, але MS насправді не дозволяє цього.
Vroo

продуктивність, це звучить жахливо, ви робите 2 критерії сортування
ColacX

У документації Microsoft, яку ви зв’язали, я прочитав, що значення IS NULL - це не вираз , а предикат . Це не те саме.
BertuPG

1
На думку Microsoft, предикат - це вираз. Це буквально перші три слова на docs.microsoft.com/en-us/sql/t-sql/queries/predicates
Vroo

3
order by -cast([Next_Contact_Date] as bigint) desc

викинути помилку, якщо Next_Contact_Dateзначення нульовеExplicit conversion from data type date to bigint is not allowed.
Nerdroid

2

Трохи пізно, але, можливо, хтось вважає це корисним.

Для мене ISNULL не могло бути і мови через сканування таблиці. UNION ALL потребував би від мене повторення складного запиту, і завдяки моєму вибору лише TOP X це було б не дуже ефективно.

Якщо ви можете змінити дизайн таблиці, ви можете:

  1. Додайте ще одне поле, лише для сортування, наприклад Next_Contact_Date_Sort.

  2. Створіть тригер, який заповнює це поле великим (або малим) значенням, залежно від того, що вам потрібно:

    CREATE TRIGGER FILL_SORTABLE_DATE ON YOUR_TABLE AFTER INSERT,UPDATE AS 
    BEGIN
        SET NOCOUNT ON;
        IF (update(Next_Contact_Date)) BEGIN
        UPDATE YOUR_TABLE SET Next_Contact_Date_Sort=IIF(YOUR_TABLE.Next_Contact_Date IS NULL, 99/99/9999, YOUR_TABLE.Next_Contact_Date_Sort) FROM inserted i WHERE YOUR_TABLE.key1=i.key1 AND YOUR_TABLE.key2=i.key2
        END
    END
    

2

Використовуйте desc і, якщо потрібно, помножте на -1. Приклад зростаючого внутрішнього впорядкування з nulls last:

select * 
from
(select null v union all select 1 v union all select 2 v) t
order by -t.v desc

Не думайте, що це буде працювати для змінних, таких як дати ..
Шарлотта Ден

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