Perché i NULL vengono ordinati per primi?


20

Perché quando abbiamo un valore NULL in una colonna e ordiniamo in base al valore crescente, i NULL vengono ordinati per primi?

select 1 as test
union all
select 2
union all
select NULL
union all
select 3
union all
select 4
order by test

risultati in

NULL
1
2
3
4

Continuo a pensare che NULL significava "indeterminato" o possibile "sconosciuto". Se questo è vero, non sarebbero ordinati per ultimi, poiché il valore potrebbe essere maggiore di tutti gli altri valori? (O questa è un'opzione di ordinamento da qualche parte?)

Sono su SQL Server 2008R2, ma sospetto che ciò sia vero su tutti i server SQL e probabilmente su tutti i RDBMS.


1
Oracle lo elenca per ultimo. Ciò mi ha incasinato una volta, credendo che dovesse comportarsi come SQL Server.
Andrei Rînea,

2
"Se questo è vero, non sarebbero ordinati per ultimi, poiché il valore potrebbe essere maggiore di tutti gli altri valori". Il valore potrebbe essere inferiore anche a tutti gli altri valori. Per me, è intuitivo che un valore falso come null dovrebbe essere nella parte inferiore. E pratico, poiché in pratica, spesso vuoi usare l' descordinamento per mostrare le cose più grandi o più recenti, nel qual caso sarei felice che le cose null siano le ultime.
mahemoff,

Il database fa quello che gli dici di fare. Se sai che i tuoi dati contengono valori null e hai qualche motivo commerciale per ordinare i dati in un certo modo, allora devi specificarli nella query o nel codice / vista che elabora / visualizza i dati. Non lasciare mai l'ordinamento fino al comportamento predefinito del database.
Nulla è necessario il

Risposte:


19

BOL : un valore NULL indica che il valore è sconosciuto. Un valore di NULL è diverso da un valore vuoto o zero. Nessun due valori null sono uguali. Il confronto tra due valori null o tra un valore NULL e qualsiasi altro valore restituisce sconosciuto perché il valore di ciascun NULL è sconosciuto.

NULL significa sconosciuto. Nessuna altra interpretazione è valida.

Se questo è vero, non sarebbero ordinati per ultimi, poiché il valore potrebbe essere maggiore di tutti gli altri valori?

Non ci potrebbe essere . Non esiste un valore potenziale . Sconosciuto è sconosciuto è sconosciuto.

Per quanto riguarda il motivo per cui appare prima, piuttosto che ultimo, questo non è soddisfatto dagli standard SQL pubblicati ed è purtroppo lasciato alla discrezione del fornitore RDBMS:

Wikipedia : lo standard SQL non definisce esplicitamente un ordinamento predefinito per Nulls. Invece, sui sistemi conformi, i valori null possono essere ordinati prima o dopo tutti i valori dei dati utilizzando rispettivamente le clausole NULLS FIRST o NULLS LAST dell'elenco ORDER BY. Tuttavia, non tutti i fornitori di DBMS implementano questa funzionalità. I fornitori che non implementano questa funzionalità possono specificare trattamenti diversi per l'ordinamento null nel DBMS.


Quindi, è una chiamata di giudizio. Questo ha molto senso. Grazie!
Richard,

6

Hai ragione che NULLpuò significare "Indeterminante" o "Unownn" o "Non ancora noto" o "Non applicabile". Ma non c'è motivo di mettere i Null prima o alla fine. Se non conosciamo i valori effettivi, allora possono essere piccoli o grandi.

Penso che lo standard per determinare il comportamento desiderato di Nulls durante l'ordinamento sia:

ORDER BY 
    test NULLS LAST                      --- or NULLS FIRST for the opposite

Sfortunatamente SQL Server non ha ancora adottato questa sintassi. Se non sbaglio PostgreSQL e Oracle ce l'hanno.

Una soluzione:

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

Un'altra soluzione che necessita di modifiche a seconda del tipo di dati, ma non si preforma bene, poiché non può utilizzare un indice su (test):

ORDER BY 
    COALESCE(test, 2147483647)               --- if it's a 4-byte signed integer

In questo modo ORDER BY COALESCE (test, 2147483647) il server SQL non può utilizzare Index.
Ardalan Shahgholi,

3

Non so perché sia stato fatto in questo modo, ma per definizione NULLS non può essere paragonato a non NULLS, quindi devono andare all'inizio o alla fine (la risposta di Mark copre questo in modo molto più dettagliato).

Per ottenere il comportamento che desideri - Per quanto ne so, non esiste un'opzione di ordinamento per mettere gli null alla fine, quindi devi evitarlo usando una colonna calcolata per forzarli per ultimi. Tuttavia, in SQL Server non è possibile ordinare in base a una colonna calcolata ( CASE WHEN ...) quando i dati contengono un operatore set ( UNION ALL). Così:

CREATE TABLE #sorttest(test int)
INSERT INTO #sorttest values(1)
INSERT INTO #sorttest values(5)
INSERT INTO #sorttest values(4)
INSERT INTO #sorttest values(NULL)
INSERT INTO #sorttest values(3)
INSERT INTO #sorttest values(2)
SELECT test
FROM #sorttest
ORDER BY CASE WHEN test IS NULL THEN 1 ELSE 0 END, test

DROP TABLE #sorttest

Funzionerà per ordinare gli null per ultimi. Se devi usare UNION(o EXCEPTo INTERSECTS) per generare il tuo set di dati, scarica i tuoi dati in una tabella temporanea come sopra.


... oppure utilizza l'output UNIONed come tabella derivata.
Andriy M

0

Se hai a che fare con numeri puoi anche usare

ORDER BY -test DESC

NULLsono i valori più bassi possibili, quindi DESCli mette alla fine. Nel frattempo i valori non nulli hanno il segno invertito, quindi in DESCrealtà è un ASCvalore reale. Questo dovrebbe essere più veloce di CASEe suppongo che Query Optimizer possa anche utilizzare gli indici su testcolonna.


3
No, non sarebbe in grado di utilizzare un indice per l'ordinamento. A meno che tu non abbia un indice sull'espressione calcolata (- test).
ypercubeᵀᴹ

1
Intelligente, anche se limitato ai soli dati numerici (appropriato comunque per l'esempio di OP). Non sono sicuro che questo sarebbe effettivamente più veloce dell'uso di CASE ma sono sicuro che non userebbe un indice (a meno che non sia quello che dice @ ypercubeᵀᴹ - ma quindi un'espressione CASE potrebbe essere indicizzata esattamente allo stesso modo).
Andriy M
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.