Data i ostatnie null SQL Server ORDER BY


82

Próbuję zamówić według daty. Chcę, aby najnowsze daty pojawiały się jako pierwsze. To dość proste, ale jest wiele rekordów, które są zerowe i poprzedzają jakiekolwiek rekordy z datą.

Próbowałem kilku rzeczy bez powodzenia:

ORDER BY ISNULL(Next_Contact_Date, 0)

ORDER BY ISNULL(Next_Contact_Date, 999999999)

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

Jak mogę porządkować według daty i mieć zerowe dane jako ostatnie? Typ danych to smalldatetime.


Czy porządek sortowania musi być rosnący, ale z zerami na końcu? Czy będziesz mieć przyszłe daty w swoim stole?
AllenG

@AllenG, tak, od przeszłości do przyszłości, najpierw przeszłość i tak dalej. Więc tak, rosnąco. Tak, przyszłe daty są tym, czym większość z nich będzie.
UpHelix

Odpowiedzi:


112

smalldatetime ma zakres do 6 czerwca 2079 r., więc możesz użyć

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

Jeśli żadne legalne rekordy nie będą miały tej daty.

Jeśli nie jest to założenie, możesz polegać na bardziej niezawodnej opcji, czyli sortowaniu w dwóch kolumnach.

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

Obie powyższe sugestie nie pozwalają jednak na użycie indeksu, aby uniknąć sortowania i przedstawić podobnie wyglądające plany.

wprowadź opis obrazu tutaj

Jest jeszcze jedna możliwość, jeśli taki indeks istnieje

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

Plan


Ta sztuczka może być również zastosowana do VARCHARpól (np. ORDER BY ISNULL(my_varchar, 'ZZZZZZ')) I jest niezwykle przydatna, szczególnie do uzyskiwania zamówień w określony sposób podczas używania GROUP BY . . . GROUPING SETS. Dzięki za opublikowanie tego.
sparc_spread

Dlaczego nie możemy użyć polecenia order by desc, aby umieścić wartości zerowe na dole? także, dlaczego mapujemy null na 1?
MasterJoe

35

Według Itzika Ben-Gana, autora T-SQL Fundamentals for MS SQL Server 2012 , „Domyślnie SQL Server sortuje znaki NULL przed wartościami innymi niż NULL . Aby uzyskać znaki NULL do sortowania jako ostatnie, możesz użyć wyrażenia CASE, które zwraca 1, gdy kolumna „ Next_Contact_Date ma wartość NULL ” i 0, gdy nie jest równa NULL . Znaki inne niż NULL uzyskują 0 z powrotem z wyrażenia; dlatego są sortowane przed znakami NULL (które otrzymują 1). To wyrażenie CASE jest używane jako pierwsze sortowanie kolumny ”. Next_Contact_Datekolumna "powinna być określona jako druga kolumna sortowania. W ten sposób niż NULL będą znaczniki są sortowane poprawnie między sobą. ”Oto zapytanie rozwiązania dla Twojego przykładu dla MS SQL Server 2012 (i SQL Server 2014):

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

Równoważny kod wykorzystujący składnię IIF:

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

Ponadto, aby dodać do odpowiedzi, jeśli zmienisz IIF 1 i 0 wokół wartości zerowych, przejdą na górę. Działa to również, jeśli chcesz wyodrębnić krotki, umieszczając je na górze tabeli.
Franco Pettigrosso

3

Jeśli Twój SQL nie obsługuje NULLS FIRSTlub NULLS LAST, najprostszym sposobem na to jest użycie value IS NULLwyrażenia:

ORDER BY Next_Contact_Date IS NULL, Next_Contact_Date

aby umieścić null na końcu ( NULLS LAST) lub

ORDER BY Next_Contact_Date IS NOT NULL, Next_Contact_Date

aby umieścić wartości zerowe z przodu. Nie wymaga to znajomości typu kolumny i jest łatwiejsze do odczytania niż CASEwyrażenie.

EDYCJA: Niestety, chociaż działa to w innych implementacjach SQL, takich jak PostgreSQL i MySQL, nie działa w MS SQL Server. Nie miałem serwera SQL do przetestowania i polegałem na dokumentacji firmy Microsoft oraz testach z innymi implementacjami SQL. Według Microsoftu value IS NULL jest to wyrażenie, które powinno być użyteczne tak jak każde inne wyrażenie. I ORDER BY ma przyjmować wyrażenia, tak jak każda inna instrukcja, która przyjmuje wyrażenie. Ale to tak naprawdę nie działa.

Dlatego najlepszym rozwiązaniem dla SQL Server wydaje się być CASEwyrażenie.


7
To nie jest poprawna składnia SQL Server
Martin Smith

3
Przepraszam za to. To powinno być ważne na dokumentację i pracuje w innym zapytania SQL firmy Microsoft, ale MS faktycznie nie pozwala na to.
Vroo

jeśli chodzi o wydajność, brzmi to okropnie, robisz dwa
rodzaje

W dokumentacji firmy Microsoft, którą utworzyłeś, czytałem, że wartość JEST NULL nie jest wyrażeniem , ale predykatem . To nie to samo.
BertuPG,

1
Według Microsoftu predykat jest wyrażeniem. To dosłownie pierwsze trzy słowa na docs.microsoft.com/en-us/sql/t-sql/queries/predicates
Vroo

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

wyrzuć błąd, jeśli Next_Contact_Datejest zerowyExplicit conversion from data type date to bigint is not allowed.
Nerdroid

2

Trochę późno, ale może komuś się przyda.

Dla mnie ISNULL nie wchodziło w grę ze względu na skanowanie tabeli. UNION ALL wymagałoby powtórzenia złożonego zapytania, a ponieważ wybrałem tylko TOP X, nie byłoby to zbyt wydajne.

Jeśli jesteś w stanie zmienić projekt stołu, możesz:

  1. Dodaj kolejne pole, tylko do sortowania, takie jak Next_Contact_Date_Sort.

  2. Utwórz regułę, która wypełni to pole dużą (lub małą) wartością, w zależności od potrzeb:

    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

Użyj desc i pomnóż przez -1, jeśli to konieczne. Przykład rosnącej kolejności int z zerami last:

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

Nie myśl, że to zadziałaby dla zmiennych takich jak daty ..
Charlotte Deng

1

Wiem, że to jest stare, ale to działa dla mnie

Order by Isnull(Date,'12/31/9999')
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.