SQL come rendere ultimi i valori null durante l'ordinamento crescente


297

Ho una tabella SQL con un campo datetime. Il campo in questione può essere nullo. Ho una query e voglio i risultati ordinati in modo crescente in base al campo datetime, tuttavia voglio righe in cui il campo datetime è nullo alla fine dell'elenco, non all'inizio.

C'è un modo semplice per farlo?



Risposte:


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

2
Si noti tuttavia che se si posiziona un indice sulla colonna di ordinamento per migliorare le prestazioni (*), questo metodo complicherà in qualche modo il piano di query e perderà gran parte del vantaggio in termini di prestazioni. * - gli indici hanno fornito i dati preordinati, evitando così un ordinamento per l'esecuzione della query. Si consiglia di filtrare i record NULL, se possibile, per evitare completamente questo problema.
redcalx,

2
Bella risposta data anche qui con tutti i modi possibili con vantaggi e svantaggi nickstips.wordpress.com/2010/09/30/…
sudhAnsu63

40
order by case when MyDate is null then 1 else 0 endè un modo molto lungo per dirloORDER BY MyDate IS NULL
Martin,

5
@Martin Nota che questa domanda non è taggata mysql. Ho fornito una soluzione generalizzata - ci sono molti modi diversi di fare la stessa cosa su diversi dbs.
RedFilter,

1
@KyleDelaney Perché order by 0viene interpretato come un indice di colonna e gli indici di colonna sono basati su 1. Per ordinare una query in base alla terza colonna puoi dire order by 3(che è una terribile idea per le query di produzione), ma molto utile (così com'è *) quando si sperimenta.
RedFilter,

159

(Un po 'in ritardo, ma questo non è stato menzionato affatto)

Non hai specificato il tuo DBMS.

In SQL standard (e DBMS più moderni come Oracle, PostgreSQL, DB2, Firebird, Apache Derby, HSQLDB e H2) è possibile specificare NULLS LASTo NULLS FIRST:

Utilizzare NULLS LASTper ordinarli fino alla fine:

select *
from some_table
order by some_column DESC NULLS LAST

16
AFAIK NULLS FIRSTe NULLS LASTsono stati aggiunti in SQL: 2003 ma non esiste un'implementazione standard disponibile nei diversi DMBS '. A seconda del motore di database, utilizzare ORDER BY expr some_column DESC NULLS LAST(Oracle), ORDER BY ISNULL(some_column, 1), some_column ASC(MSSQL) o ORDER BY ISNULL(some_column), some_column ASC(MySQL con un'implementazione ISNULL () diversa).
SaschaM78,

3
@ SaschaM78: l'ordinamento predefinito dei NULL dipende da DBMS. Alcuni li ordinano alla fine, altri all'inizio. Alcuni non si preoccupano ASC/ DESCcon i null altri. Quindi l'unico modo per garantire ciò è utilizzare NULL FIRST/LAST se il DBMS lo supporta. At documenta ciò che intendi. L'utilizzo di isnull()o altre funzioni è una soluzione alternativa per il supporto mancante per NULLS FIRST/LAST(che è supportato da Oracle, PostgreSQL, DB2, Firebird, Apache Derby, HSQLDB e H2)
a_horse_with_no_name

Hai perfettamente ragione, volevo solo aggiungere il fatto che ci sono alcuni DBMS in giro che non seguono lo standard (ancora) o hanno le loro specialità come Oracle che richiedono la exprparola chiave quando si utilizza NULLS FIRST / LAST. E grazie al fatto che i null mostrati per primi / ultimi variano da un tipo di database all'altro, non lo sapevo!
SaschaM78,

2
Sembra promettente, ma purtroppo l'ho provato e NULLS LASTnon ha funzionato nel mio database MySQL.
AmmiraglioTrawn

1
@AdmiralAdama: puoi sempre passare a Postgres
a_horse_with_no_name


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

10
Mentre questo generalmente funzionerà, va notato che questa risposta ha alcuni problemi: una grande data in futuro potrebbe scontrarsi o essere inferiore ai dati reali, risultando in un ordinamento imperfetto. Inoltre, si tratta di una soluzione di "numero magico" che non si auto documenta.
RedFilter,

Questa sembra essere un'ottima alternativa alla risposta @RedFilter quando devi confrontare la colonna in questione con un'altra colonna della data. Lo uso per l'elenco di anzianità sindacale. Se il dipendente ha una data qualificata (che è nullable), le bolle di quella data vengono registrate in alto, altrimenti usa HireDate. L'uso di ORDER BY ISNULL (QualifiedDate, '1-1-2099'), HireDate, LastName, ecc. Rende la data qualificata non in conflitto con la data HiredDate e viene prodotto l'elenco di senirity corretto.
Alan Fisher,

14

È possibile utilizzare la funzione integrata per verificare la presenza di null o non null, come di seguito. Lo collaudo e funziona benissimo.

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


Perché le date funzionino con mssql ho trovato utile inserire una data lontana in futuro nella funzione ISNULL, cioè ISNULL (MyDate, '2100-01-01')
Emi-C,

In MySQL, dice che sto passando troppi parametri. Ho ottenuto questo da analizzare facendo ISNULL(MyDate) DESC, MyDate ASC, ma non è stato ordinato nell'ordine corretto.
AmmiraglioTrawn

12

Se il tuo motore lo consente ORDER BY x IS NULL, xo ORDER BY x NULLS LASTutilizzalo. Ma in caso contrario questi potrebbero aiutare:

Se stai ordinando per tipo numerico puoi farlo: (Prendendo in prestito lo schema da un'altra risposta .)

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

risultati visualizzati ordinati per DepartmentId con valori null ultimi

Qualsiasi numero non nullo diventa 0 e i valori null diventano 1, che ordina i valori nulli per ultimi.

Puoi anche farlo per le stringhe:

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

risultati visualizzati ordinati per LastName con valori null ultimi

Perché 'a'> ''.

Funziona anche con le date convertendo in un int nullable e usando il metodo per gli ints sopra:

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

(Facciamo finta che lo schema abbia HireDate.)

Questi metodi evitano il problema di dover inventare o gestire un valore "massimo" di ogni tipo o correggere le query se il tipo di dati (e il massimo) cambia (entrambi i problemi che subiscono altre soluzioni ISNULL). Inoltre sono molto più brevi di un CASO.


Funziona alla grande ! Grazie
Vani,

8

Quando la colonna del tuo ordine è numerica (come una classifica) puoi moltiplicarla per -1 e quindi ordinare in ordine decrescente. Manterrà l'ordine che ti aspetti, ma inserisce NULL per ultimo.

select *
from table
order by -rank desc

Stavo per commentare questo. L'ho imparato da stackoverflow.com/a/8174026/1193304 ed è fantastico
Chris,


3

Grazie a RedFilter per aver fornito un'ottima soluzione al problema del bugging dell'ordinamento del campo datetime nullable.

Sto usando il database SQL Server per il mio progetto.

La modifica del valore null datetime su '1' risolve il problema dell'ordinamento per la colonna tipo di dati datetime. Tuttavia, se abbiamo una colonna con un tipo di dati diverso da datetime, allora non riesce a gestirlo.

Per gestire un ordinamento di colonne varchar, ho provato a usare "ZZZZZZZ" poiché sapevo che la colonna non ha valori che iniziano con "Z". Ha funzionato come previsto.

Sulle stesse linee, ho usato i valori massimi +1 per int e altri tipi di dati per ottenere l'ordinamento come previsto. Questo mi ha dato anche i risultati richiesti.

Tuttavia, sarebbe sempre l'ideale per ottenere qualcosa di più semplice nel motore di database stesso che potrebbe fare qualcosa del tipo:

Order by Col1 Asc Nulls Last, Col2 Asc Nulls First 

Come indicato nella risposta fornita da a_horse_with_no_name.



3

Se stai usando MariaDB, menzionano quanto segue nella documentazione dei valori NULL .

ordinazione

Quando si ordina da un campo che può contenere valori NULL, tutti i NULL vengono considerati con il valore più basso. Quindi, l'ordine in ordine DESC vedrà i NULL apparire per ultimi. Per forzare i NULL a essere considerati come valori più alti, si può aggiungere un'altra colonna che ha un valore più alto quando il campo principale è NULL. Esempio:

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

Ordine decrescente, prima con i NULL:

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

Tutti i valori NULL sono anche considerati equivalenti ai fini delle clausole DISTINCT e GROUP BY.

Quanto sopra mostra due modi per ordinare in base a valori NULL, è possibile combinarli anche con le parole chiave ASC e DESC. Ad esempio, l'altro modo per ottenere prima i valori NULL sarebbe:

SELECT col1 FROM tab ORDER BY ISNULL(col1) DESC, col1;
--                                         ^^^^

2

La soluzione che usa il "case" è universale, ma non usa gli indici.

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

Nel mio caso, avevo bisogno di prestazioni.

 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
Se sei interessato alle prestazioni, dovresti utilizzare UNION ALL.
RedFilter,


Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.