SQL, wie Nullwerte beim Sortieren aufsteigend zuletzt verwendet werden

297

Ich habe eine SQL-Tabelle mit einem Datum / Uhrzeit-Feld. Das betreffende Feld kann null sein. Ich habe eine Abfrage und möchte, dass die Ergebnisse aufsteigend nach dem Datum / Uhrzeit-Feld sortiert werden. Ich möchte jedoch Zeilen, bei denen das Datum / Uhrzeit-Feld am Ende der Liste und nicht am Anfang Null ist.

Gibt es einen einfachen Weg, dies zu erreichen?

David Božjak
quelle

Antworten:

394
select MyDate
from MyTable
order by case when MyDate is null then 1 else 0 end, MyDate
RedFilter
quelle
2
Beachten Sie jedoch, dass diese Methode den Abfrageplan etwas kompliziert und einen Großteil des Leistungsvorteils verliert, wenn Sie einen Index in die Sortierspalte einfügen, um die Leistung zu verbessern (*). * - Indizes lieferten die Daten vorsortiert, wodurch eine Sortierung pro Abfrageausführung vermieden wurde. Es ist ratsam, die NULL-Datensätze nach Möglichkeit herauszufiltern, um dieses Problem vollständig zu vermeiden.
Redcalx
2
Schöne Antwort auch hier mit allen möglichen Möglichkeiten mit Vor- und Nachteilen nickstips.wordpress.com/2010/09/30/…
sudhAnsu63
40
order by case when MyDate is null then 1 else 0 endist eine wirklich lange Art zu sagenORDER BY MyDate IS NULL
Martin
5
@ Martin Beachten Sie, dass diese Frage nicht mit MySQL gekennzeichnet ist. Ich habe eine verallgemeinerte Lösung bereitgestellt - es gibt viele verschiedene Möglichkeiten, dasselbe über verschiedene Datenbankbereiche hinweg zu tun.
RedFilter
1
@KyleDelaney Da order by 0wird als Spaltenindex interpretiert und die Spaltenindizes basieren auf 1. Um eine Abfrage nach der 3. Spalte zu sortieren, können Sie sagen order by 3(was eine schreckliche Idee für Produktionsabfragen ist), aber sehr praktisch (wie es ist *) beim Experimentieren.
RedFilter
159

(Ein bisschen zu spät, aber das wurde überhaupt nicht erwähnt)

Sie haben Ihr DBMS nicht angegeben.

In Standard-SQL (und den meisten modernen DBMS wie Oracle, PostgreSQL, DB2, Firebird, Apache Derby, HSQLDB und H2) können Sie Folgendes angeben NULLS LASToder NULLS FIRST:

Verwenden Sie NULLS LAST, um sie bis zum Ende zu sortieren:

select *
from some_table
order by some_column DESC NULLS LAST
ein Pferd ohne Name
quelle
16
AFAIK NULLS FIRSTund NULLS LASTwurden in SQL: 2003 hinzugefügt, es ist jedoch keine Standardimplementierung für die verschiedenen DMBS verfügbar. Verwenden Sie je nach Datenbankmodul ORDER BY expr some_column DESC NULLS LAST(Oracle), ORDER BY ISNULL(some_column, 1), some_column ASC(MSSQL) oder ORDER BY ISNULL(some_column), some_column ASC(MySQL mit einer anderen ISNULL () -Implementierung).
SaschaM78
3
@ SaschaM78: Die Standardsortierung von NULL-Werten ist DBMS-abhängig. Einige sortieren sie am Ende, andere am Anfang. Einige kümmern sich nicht um ASC/ DESCmit Nullen, andere tun es. Die einzige Möglichkeit, dies sicherzustellen, ist die Verwendung, NULL FIRST/LAST wenn das DBMS dies unterstützt. Darin dokumentiert, was Sie vorhaben. Die Verwendung von isnull()oder anderer Funktionen ist eine Problemumgehung für die fehlende Unterstützung für NULLS FIRST/LAST(die von Oracle, PostgreSQL, DB2, Firebird, Apache Derby, HSQLDB und H2 unterstützt wird)
a_horse_with_no_name
Sie haben vollkommen recht, ich wollte nur die Tatsache hinzufügen, dass es einige DBMS gibt, die (noch) nicht dem Standard entsprechen oder deren Besonderheiten wie Oracle das exprSchlüsselwort erfordern, wenn NULLS FIRST / LAST verwendet wird. Und danke, dass die Nullen zuerst / zuletzt angezeigt werden und von Datenbanktyp zu Typ variieren, wusste das nicht!
SaschaM78
2
Das sieht vielversprechend aus, aber leider habe ich es versucht und NULLS LASTin meiner MySQL-Datenbank nicht funktioniert.
AdmiralThrawn
1
@AdmiralAdama: Sie können jederzeit auf Postgres upgraden
a_horse_with_no_name
35

Ich bin auch nur darauf gestoßen und das Folgende scheint mir bei MySQL und PostgreSQL zu helfen:

ORDER BY date IS NULL, date DESC

wie unter https://stackoverflow.com/a/7055259/496209 zu finden

Luksurious
quelle
Das sieht vielversprechend, aber leider habe ich versucht , es und IS NULLund IS NOT NULLhat nicht funktioniert in meiner MySQL - Datenbank.
AdmiralThrawn
14
order by coalesce(date-time-field,large date in future)
Gratzy
quelle
10
Obwohl dies im Allgemeinen funktioniert, sollte beachtet werden, dass diese Antwort einige Probleme aufweist: Ein großes Datum kann in Zukunft mit tatsächlichen Daten kollidieren oder darunter liegen, was zu einer unvollständigen Sortierung führt. Es ist auch eine "magische Zahl" -Lösung, die sich nicht selbst dokumentiert.
RedFilter
Dies ist eine großartige Alternative zur @ RedFilter-Antwort, wenn Sie die betreffende Spalte mit einer anderen Datumsspalte vergleichen müssen. Ich benutze dies für die Dienstalterliste der Gewerkschaften. Wenn der Mitarbeiter ein qualifiziertes Datum hat (das auf Null gesetzt werden kann), werden diese Datumsblasen nach oben aufgezeichnet. Andernfalls verwenden Sie HireDate. Wenn Sie ORDER BY ISNULL (QualifiedDate, '1-1-2099'), HireDate, LastName usw. verwenden, wird das Qualified-Datum nicht mit dem HiredDate-Datum in Konflikt gebracht und die richtige Seniritätsliste erstellt.
Alan Fisher
14

Sie können die integrierte Funktion verwenden, um wie folgt nach null oder nicht null zu suchen. Ich teste es und es funktioniert gut.

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

Majdi M. Aburahelah
quelle
Für Daten, die mit mssql funktionieren, fand ich es nützlich, in der ISNULL-Funktion, dh ISNULL (MyDate, '2100-01-01')
Emi-C,
In MySQL heißt es, dass ich zu viele Parameter übergebe. Ich habe dies zum Parsen gebracht ISNULL(MyDate) DESC, MyDate ASC, aber es wurde nicht in der richtigen Reihenfolge sortiert.
AdmiralThrawn
12

Wenn Ihr Motor dies zulässt ORDER BY x IS NULL, xoder ORDER BY x NULLS LASTverwendet. Wenn dies nicht der Fall ist, können diese helfen:

Wenn Sie nach einem numerischen Typ sortieren, können Sie Folgendes tun: (Ausleihen des Schemas aus einer anderen Antwort .)

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

Ergebnisanzeige sortiert nach DepartmentId mit den letzten Nullen

Jede Nicht-Null-Zahl wird zu 0, und Nullen werden zu 1, wodurch die Nullen zuletzt sortiert werden.

Sie können dies auch für Zeichenfolgen tun:

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

Ergebnisanzeige sortiert nach Nachname mit Nullen zuletzt

Weil 'a'> ''.

Dies funktioniert sogar mit Datumsangaben, indem ein nullbares int erzwungen wird und die oben beschriebene Methode für Ints verwendet wird:

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

(Stellen wir uns vor, das Schema hat HireDate.)

Diese Methoden vermeiden das Problem, einen "Maximalwert" für jeden Typ erstellen oder verwalten zu müssen oder Abfragen zu korrigieren, wenn sich der Datentyp (und das Maximum) ändert (beide Probleme, unter denen andere ISNULL-Lösungen leiden). Außerdem sind sie viel kürzer als ein Fall.

Infogulch
quelle
Funktioniert super ! Vielen Dank
Vani
8

Wenn Ihre Bestellspalte numerisch ist (wie ein Rang), können Sie sie mit -1 multiplizieren und dann absteigend sortieren. Es behält die Reihenfolge bei, die Sie erwarten, setzt aber zuletzt NULL.

select *
from table
order by -rank desc
Luizgrs
quelle
War gerade dabei, dies zu kommentieren. Ich habe es von stackoverflow.com/a/8174026/1193304 gelernt und es ist großartig
Chris
4
SELECT *          
FROM Employees
ORDER BY ISNULL(DepartmentId, 99999);

Siehe diesen Blog-Beitrag .

user3923117
quelle
3

Vielen Dank an RedFilter für die hervorragende Lösung des Fehlerproblems beim Sortieren von nullbaren Datums- / Uhrzeitfeldern.

Ich verwende die SQL Server-Datenbank für mein Projekt.

Das Ändern des Datetime-Nullwerts in '1' löst das Problem der Sortierung nach Datetime-Datentypspalte. Wenn wir jedoch eine Spalte mit einem anderen Datentyp als datetime haben, kann diese nicht verarbeitet werden.

Um eine varchar-Spaltensortierung zu handhaben, habe ich versucht, 'ZZZZZZZ' zu verwenden, da ich wusste, dass die Spalte keine Werte hat, die mit 'Z' beginnen. Es hat wie erwartet funktioniert.

In den gleichen Zeilen habe ich Maximalwerte +1 für int und andere Datentypen verwendet, um die Sortierung wie erwartet zu erhalten. Dies gab mir auch die erforderlichen Ergebnisse.

Es wäre jedoch immer ideal, im Datenbankmodul selbst etwas einfacher zu machen, das Folgendes bewirken könnte:

Order by Col1 Asc Nulls Last, Col2 Asc Nulls First 

Wie in der Antwort von a_horse_with_no_name erwähnt.

Kasim Husaini
quelle
3

In Oracle können Sie Folgendes verwenden NULLS FIRSToder NULLS LAST: Gibt an, dass NULL-Werte vor / nach Nicht-NULL-Werten zurückgegeben werden sollen:

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

Zum Beispiel:

ORDER BY date DESC NULLS LAST

Ref: http://docs.oracle.com/javadb/10.8.3.0/ref/rrefsqlj13658.html

Joaquinglezsantos
quelle
3

Wenn Sie MariaDB verwenden, wird in der Dokumentation zu NULL-Werten Folgendes erwähnt .

Bestellung

Wenn Sie nach einem Feld bestellen, das NULL-Werte enthalten kann, wird davon ausgegangen, dass alle NULL-Werte den niedrigsten Wert haben. Wenn Sie also in DESC-Reihenfolge bestellen, werden die NULL-Werte zuletzt angezeigt. Um zu erzwingen, dass NULL-Werte als höchste Werte betrachtet werden, kann eine weitere Spalte hinzugefügt werden, die einen höheren Wert hat, wenn das Hauptfeld NULL ist. Beispiel:

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

Absteigende Reihenfolge, mit NULL zuerst:

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

Alle NULL-Werte werden auch für die Zwecke der Klauseln DISTINCT und GROUP BY als gleichwertig angesehen.

Das Obige zeigt zwei Möglichkeiten zum Ordnen nach NULL-Werten. Sie können diese auch mit den Schlüsselwörtern ASC und DESC kombinieren. Der andere Weg, um zuerst die NULL-Werte zu erhalten, wäre beispielsweise:

SELECT col1 FROM tab ORDER BY ISNULL(col1) DESC, col1;
--                                         ^^^^
3limin4t0r
quelle
2

Die Lösung mit dem "Fall" ist universell, verwenden Sie dann jedoch nicht die Indizes.

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

In meinem Fall brauchte ich Leistung.

 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
quelle
1
Wenn Sie an Leistung interessiert sind, sollten Sie verwenden UNION ALL.
RedFilter
0
order by -cast([nativeDateModify] as bigint) desc
Paparazzo
quelle