Por que os NULLs são classificados primeiro?

20

Por que quando temos um valor NULL em uma coluna e ordenamos pelo valor crescente, os NULLs são classificados primeiro?

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

resulta em

NULL
1
2
3
4

Eu continuo pensando que NULL significava "Indeterminado" ou possível "Desconhecido". Se isso é verdade, eles não classificariam por último, já que o valor poderia ser maior que todos os outros valores? (Ou essa é uma opção de classificação em algum lugar?)

Estou no SQL Server 2008R2, mas suspeito que isso seja verdade em todos os servidores SQL e provavelmente em todos os RDBMSs.

Richard
fonte
11
Oracle lista por último. Isso me ferrou uma vez, acreditando que deveria se comportar como o SQL Server.
Andrei Rînea 16/03/2012
2
"Se isso é verdade, eles não classificariam por último, já que o valor poderia ser maior que todos os outros valores". O valor também pode ser menor que todos os outros valores. Para mim, é intuitivo que um valor falsey como null esteja no limite inferior. E prático, já que, na prática, muitas vezes você deseja usar a descordem para mostrar as coisas maiores ou mais recentes; nesse caso, eu ficaria feliz que as coisas nulas fossem as últimas.
mahemoff
O banco de dados faz o que você pede. Se você souber que seus dados contêm nulos e tiver algum motivo comercial para classificar os dados de uma certa maneira, será necessário especificar isso na consulta ou no código / exibição que processa / exibe os dados. Nunca deixe a classificação de acordo com o comportamento padrão do banco de dados.
nothingisnecessary

Respostas:

19

BOL : um valor NULL indica que o valor é desconhecido. Um valor NULL é diferente de um valor vazio ou zero. Não há dois valores nulos iguais. Comparações entre dois valores nulos, ou entre um NULL e qualquer outro valor, retornam desconhecidos porque o valor de cada NULL é desconhecido.

NULL significa desconhecido. Nenhuma outra interpretação é válida.

Se isso é verdade, eles não classificariam por último, já que o valor poderia ser maior que todos os outros valores?

Não pode haver . Não há valor potencial . Desconhecido é desconhecido é desconhecido.

Quanto ao motivo pelo qual aparece primeiro, e não por último, isso não é atendido pelos padrões SQL publicados e infelizmente é deixado a critério do fornecedor do RDBMS:

Wikipedia : O padrão SQL não define explicitamente uma ordem de classificação padrão para Nulos. Em vez disso, em sistemas conformes, os Nulos podem ser classificados antes ou depois de todos os valores de dados usando as cláusulas NULLS FIRST ou NULLS LAST da lista ORDER BY, respectivamente. Nem todos os fornecedores de DBMS implementam essa funcionalidade, no entanto. Os fornecedores que não implementam essa funcionalidade podem especificar tratamentos diferentes para a classificação nula no DBMS.

Mark Storey-Smith
fonte
Então, é uma decisão judicial. Isso faz muito sentido. Obrigado!
Richard
6

Você está certo que NULLpode significar 'Indeterminado' ou 'Desconhecido' ou 'Ainda não conhecido' ou 'Não se aplica'. Mas não há razão para colocar os nulos em primeiro ou último. Se não soubermos os valores reais, eles podem ser pequenos ou grandes.

Eu acho que o padrão para determinar o comportamento desejado dos Nulos durante a classificação é:

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

Infelizmente, o SQL-Server ainda não adotou esta sintaxe. Se não estou errado, o PostgreSQL e a Oracle têm.

Uma solução:

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

Outra solução que precisa de ajuste, dependendo do tipo de dados - mas não será executada corretamente, pois não pode usar um índice em (test):

ORDER BY 
    COALESCE(test, 2147483647)               --- if it's a 4-byte signed integer
ypercubeᵀᴹ
fonte
Dessa maneira, ORDER BY COALESCE (test, 2147483647) O SQL server não pode usar o Index.
Ardalan Shahgholi 4/11
3

Não sei por que isso foi feito dessa maneira, mas, por definição, NULLS não pode ser comparado a não NULLS, então eles precisam ir no início ou no final (a resposta de Mark cobre isso com muito mais detalhes).

Para obter o comportamento que você deseja - Até onde eu sei, não há opção de classificação para colocar os nulos por último, então você deve evitá-lo usando uma coluna computada para forçá-los a durar. No entanto, no SQL Server, você não pode solicitar por uma coluna computada ( CASE WHEN ...) quando seus dados contiverem um operador definido ( UNION ALL). Tão:

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

Funcionará para classificar os nulos por último. Se você precisar usar UNION(ou EXCEPTou INTERSECTS) para gerar seu conjunto de dados, despeje-os em uma tabela temporária como acima.

Simon Righarts
fonte
... ou use a saída UNIONed como uma tabela derivada.
Andriy H
0

Se você está lidando com números, também pode usar

ORDER BY -test DESC

NULLsão os valores mais baixos possíveis, portanto os DESCcoloca no final. Enquanto isso, os valores não nulos têm o sinal invertido, então DESCna verdade é um ASCdos valores reais. Isso deve ser mais rápido CASEe suponho que o otimizador de consulta também possa usar índices na testcoluna.

Luca
fonte
3
Não, não seria possível usar um índice para a classificação. A menos que você tenha um índice na expressão calculada (- test).
usar o seguinte comando
11
Inteligente, embora limitado apenas a dados numéricos (apropriado para o exemplo do OP de qualquer maneira). Não tenho certeza se isso seria realmente mais rápido do que usar CASE, mas tenho certeza de que não usaria um índice (a menos que seja o que @ ypercubeᵀᴹ diz - mas uma expressão CASE poderia ser indexada exatamente da mesma maneira).
Andriy H