SQL Server ORDER BY Datum und Nullen zuletzt

82

Ich versuche nach Datum zu bestellen. Ich möchte, dass die neuesten Daten zuerst eingehen. Das ist einfach genug, aber es gibt viele Datensätze, die null sind und die vor Datensätzen stehen, die ein Datum haben.

Ich habe ein paar Dinge ohne Erfolg versucht:

ORDER BY ISNULL(Next_Contact_Date, 0)

ORDER BY ISNULL(Next_Contact_Date, 999999999)

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

Wie kann ich nach Datum bestellen und habe die Nullen zuletzt eingegeben? Der Datentyp ist smalldatetime.

UpHelix
quelle
Muss die Sortierreihenfolge aufsteigend sein, aber mit Nullen am Ende? Und werden Sie zukünftige Daten in Ihrer Tabelle haben?
AllenG
@ AllenG, ja, von Vergangenheit zu Zukunft mit Vergangenheit zuerst und so weiter. Also ja, aufsteigend. Ja, zukünftige Daten sind das, was die meisten von ihnen sein werden.
UpHelix

Antworten:

112

smalldatetime hat Reichweite bis zum 6. Juni 2079, so dass Sie verwenden können

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

Wenn keine legitimen Aufzeichnungen dieses Datum haben.

Wenn dies keine Annahme ist, bei der Sie sich auf eine robustere Option verlassen möchten, wird nach zwei Spalten sortiert.

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

Beide oben genannten Vorschläge können jedoch keinen Index verwenden, um eine Sortierung zu vermeiden und ähnlich aussehende Pläne zu erstellen.

Geben Sie hier die Bildbeschreibung ein

Eine andere Möglichkeit, wenn ein solcher Index existiert, ist

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

Planen

Martin Smith
quelle
Dieser Trick kann auch auf VARCHARFelder angewendet werden (z. B. ORDER BY ISNULL(my_varchar, 'ZZZZZZ')) und ist äußerst nützlich, insbesondere um Aufträge auf eine bestimmte Weise zu erhalten, wenn sie verwendet werden GROUP BY . . . GROUPING SETS. Vielen Dank für die Veröffentlichung.
sparc_spread
Warum können wir order by desc nicht verwenden, um Nullen am unteren Rand zu setzen? Warum ordnen wir null null zu?
MasterJoe
35

Laut Itzik Ben-Gan, Autor von T-SQL Fundamentals für MS SQL Server 2012 , "sortiert SQL Server standardmäßig NULL- Zeichen vor Nicht- NULL- Werten. Um NULL- Zeichen zum letzten Sortieren zu erhalten, können Sie einen CASE- Ausdruck verwenden, der zurückgibt 1, wenn die Spalte " Next_Contact_Date " NULL ist , und 0, wenn sie nicht NULL ist . Nicht- NULL- Markierungen erhalten 0 vom Ausdruck zurück, daher werden sie vor NULL- Markierungen sortiert (die 1 erhalten). Dieser CASE- Ausdruck wird als erster verwendet Spalte sortieren. " Das Next_Contact_DateSpalte "sollte als zweite Sortierspalte angegeben werden. Auf diese Weise werden Nicht- NULL- Markierungen untereinander korrekt sortiert." Hier ist die Lösungsabfrage für Ihr Beispiel für MS SQL Server 2012 (und SQL Server 2014):

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

Äquivalenter Code mit IIF-Syntax:

ORDER BY 
   IIF(Next_Contact_Date IS NULL, 1, 0),
   Next_Contact_Date;
Andy
quelle
Um die Antwort zu ergänzen, werden die Nullen 1 und 0 der IIF um die Nullen herum nach oben verschoben. Dies funktioniert auch, wenn Sie einzelne Tupel auswählen möchten, indem Sie sie oben auf den Tisch legen.
Franco Pettigrosso
3

Wenn Ihr SQL nicht unterstützt NULLS FIRSToder nicht NULLS LAST, verwenden Sie am einfachsten den folgenden value IS NULLAusdruck:

ORDER BY Next_Contact_Date IS NULL, Next_Contact_Date

die Nullen am Ende setzen ( NULLS LAST) oder

ORDER BY Next_Contact_Date IS NOT NULL, Next_Contact_Date

die Nullen nach vorne setzen. Dies erfordert keine Kenntnis des Spaltentyps und ist leichter zu lesen als der CASEAusdruck.

BEARBEITEN: Leider funktioniert dies in anderen SQL-Implementierungen wie PostgreSQL und MySQL, in MS SQL Server jedoch nicht. Ich hatte keinen SQL Server zum Testen und verließ mich auf die Dokumentation von Microsoft und das Testen mit anderen SQL-Implementierungen. Laut Microsoft value IS NULL ist dies ein Ausdruck , der wie jeder andere Ausdruck verwendet werden kann. Und ORDER BY soll Ausdrücke nehmen wie jede andere Aussage, die einen Ausdruck nimmt. Aber es funktioniert nicht wirklich.

Die beste Lösung für SQL Server scheint daher der CASEAusdruck zu sein.

Vroo
quelle
7
Dies ist keine gültige SQL Server-Syntax
Martin Smith
3
Das tut mir leid. Es sollte gemäß Microsoft-Dokumentation gültig sein und in anderen SQLs funktionieren, aber MS lässt es nicht zu.
Vroo
In
Bezug auf die
In der von Ihnen verlinkten Microsoft-Dokumentation habe ich gelesen, dass der Wert IS NULL kein Ausdruck , sondern ein Prädikat ist . Es ist nicht das gleiche.
BertuPG
1
Laut Microsoft ist ein Prädikat ein Ausdruck. Das sind buchstäblich die ersten drei Wörter unter docs.microsoft.com/en-us/sql/t-sql/queries/predicates
Vroo
3
order by -cast([Next_Contact_Date] as bigint) desc
Paparazzo
quelle
werfen Sie einen Fehler, wenn Next_Contact_Datenull istExplicit conversion from data type date to bigint is not allowed.
Nerdroid
2

Ein bisschen spät, aber vielleicht findet es jemand nützlich.

Für mich kam ISNULL aufgrund des Tabellenscans nicht in Frage. UNION ALL würde mich brauchen, um eine komplexe Abfrage zu wiederholen, und da ich nur das TOP X ausgewählt hätte, wäre es nicht sehr effizient gewesen.

Wenn Sie das Tischdesign ändern können, können Sie:

  1. Fügen Sie ein weiteres Feld hinzu, nur zum Sortieren, z. B. Next_Contact_Date_Sort.

  2. Erstellen Sie einen Trigger, der dieses Feld mit einem großen (oder kleinen) Wert füllt, je nachdem, was Sie benötigen:

    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
    
Aaa
quelle
2

Verwenden Sie desc und multiplizieren Sie gegebenenfalls mit -1. Beispiel für aufsteigende int-Reihenfolge mit Nullen zuletzt:

select * 
from
(select null v union all select 1 v union all select 2 v) t
order by -t.v desc
Ulf Herrmann
quelle
Denken Sie nicht, dass dies für Variablen wie Daten funktionieren würde.
Charlotte Deng
1

Ich weiß, das ist alt, aber das hat bei mir funktioniert

Order by Isnull(Date,'12/31/9999')
anonym
quelle