SQL como fazer com que valores nulos venham por último ao classificar em ordem crescente


297

Eu tenho uma tabela SQL com um campo de data e hora. O campo em questão pode ser nulo. Eu tenho uma consulta e quero que os resultados sejam classificados de forma crescente pelo campo datetime, no entanto, quero linhas em que o campo datetime é nulo no final da lista, não no início.

Existe uma maneira simples de conseguir isso?



Respostas:


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

2
Observe, no entanto, que se você colocar um índice na coluna de classificação para melhorar o desempenho (*), esse método complicará um pouco o plano de consulta e perderá muito do benefício de desempenho. * - os índices forneceram os dados pré-selecionados, evitando assim uma classificação por execução de consulta. É aconselhável filtrar os registros NULL, se possível, para evitar esse problema completamente.
Redcalx #

2
Resposta bom também dada aqui com todas as formas possíveis com Vantagens e Desvantagens nickstips.wordpress.com/2010/09/30/...
sudhAnsu63

40
order by case when MyDate is null then 1 else 0 endé realmente uma maneira muito longa de dizer #ORDER BY MyDate IS NULL
Martin

5
@ Martin Note que esta pergunta não está etiquetada como mysql. Forneci uma solução generalizada - existem muitas maneiras diferentes de fazer a mesma coisa em diferentes dbs.
RedFilter

1
@KyleDelaney Porque order by 0é interpretado como um índice de coluna e os índices da coluna são baseados em 1. Para classificar uma consulta pela 3ª coluna, você pode dizer order by 3(o que é uma péssima idéia para consultas de produção), mas muito útil (como é *) ao experimentar.
RedFilter

159

(Um "pouco" tarde, mas isso não foi mencionado)

Você não especificou seu DBMS.

No SQL padrão (e nos DBMS mais modernos, como Oracle, PostgreSQL, DB2, Firebird, Apache Derby, HSQLDB e H2), você pode especificar NULLS LASTou NULLS FIRST:

Use NULLS LASTpara classificá-los até o fim:

select *
from some_table
order by some_column DESC NULLS LAST

16
AFAIK NULLS FIRSTe NULLS LASTforam adicionados no SQL: 2003, mas não há implementação padrão disponível nos diferentes DMBS '. Dependendo do mecanismo do banco de dados, use ORDER BY expr some_column DESC NULLS LAST(Oracle), ORDER BY ISNULL(some_column, 1), some_column ASC(MSSQL) ou ORDER BY ISNULL(some_column), some_column ASC(MySQL com uma implementação ISNULL () diferente).
precisa saber é o seguinte

3
@ SaschaM78: a classificação padrão de NULLs depende do DBMS. Alguns os classificam no final, outros no começo. Alguns não se preocupam com ASC/ DESCcom nulos, outros sim. Portanto, a única maneira de garantir isso é usar NULL FIRST/LAST se o DBMS suportar. Nele documenta o que você pretende. O uso de isnull()ou outras funções é uma solução para o apoio faltando para NULLS FIRST/LAST(que é suportado pela Oracle, PostgreSQL, DB2, Firebird, Apache Derby, HSQLDB e H2)
a_horse_with_no_name

Você está perfeitamente certo, eu só queria acrescentar o fato de que existem alguns DBMS que ainda não seguem o padrão (ainda) ou têm suas especialidades, como Oracle, exigindo a exprpalavra - chave ao usar NULLS PRIMEIRO / ÚLTIMO. E obrigado por os nulos serem mostrados primeiro / último variando de tipo para banco de dados, não sabia disso!
SaschaM78

2
Isso parece promissor, mas, infelizmente, eu tentei e NULLS LASTnão funcionou no meu banco de dados MySQL.
AdmiralThrawn

1
@AdmiralAdama: você sempre pode atualizar para Postgres
a_horse_with_no_name


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

10
Embora isso geralmente funcione, deve-se notar que esta resposta tem alguns problemas: data grande no futuro pode colidir com ou ser menor que os dados reais, resultando em uma classificação imperfeita. Além disso, é uma solução de "número mágico" que não é auto-documentada.
RedFilter 30/09/09

Essa é uma ótima alternativa para a resposta do @RedFilter quando você precisar comparar a coluna em questão com outra coluna de data. Eu uso isso para a lista de antiguidade do sindicato. Se o funcionário tiver uma data Qualificada (que é anulável), essa data será registrada na parte superior, caso contrário, use HireDate. O uso de ORDER BY ISNULL (QualifiedDate, '1-1-2099'), HireDate, LastName etc. faz com que a data Qualificada não entre em conflito com a data HiredDate e a lista de seniridades correta é produzida.
Alan Fisher

14

Você pode usar a função interna para verificar se é nulo ou não nulo, como abaixo. Eu testo e está funcionando bem.

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


Para datas de trabalhar com mssql eu achei útil colocar um longe na data futura na função ISNULL ou seja ISNULL (MyDate, '2100/01/01')
Emi-C

No MySQL, diz que estou passando muitos parâmetros. Consegui analisar isso ISNULL(MyDate) DESC, MyDate ASC, mas ele não foi classificado na ordem correta.
AdmiralThrawn

12

Se o seu mecanismo permitir ORDER BY x IS NULL, xou ORDER BY x NULLS LASTusar isso. Mas se isso não acontecer, isso pode ajudar:

Se você estiver classificando por um tipo numérico, faça o seguinte: (Emprestando o esquema de outra resposta .)

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

resultado mostrando classificado por DepartmentId com os últimos nulos

Qualquer número não nulo torna-se 0 e nulos tornam-se 1, que classifica os nulos por último.

Você também pode fazer isso para seqüências de caracteres:

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

resultado mostrando classificado por Sobrenome com nulos por último

Porque 'a'> ''.

Isso funciona mesmo com datas coagindo para um int nulo e usando o método para ints acima:

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

(Vamos fingir que o esquema tem HireDate.)

Esses métodos evitam a questão de ter que criar ou gerenciar um valor "máximo" de cada tipo ou corrigir consultas se o tipo de dados (e o máximo) mudar (ambos os problemas que outras soluções ISNULL sofrem). Além disso, eles são muito mais curtos que um CASE.


Funciona bem ! Obrigado
Vani

8

Quando a coluna do seu pedido é numérica (como uma classificação), você pode multiplicá-la por -1 e, em seguida, decrescente. Ele manterá a ordem que você está esperando, mas colocará NULL por último.

select *
from table
order by -rank desc

Estava prestes a comentar isso. Aprendi com stackoverflow.com/a/8174026/1193304 e é ótimo
Chris


3

Agradecemos à RedFilter por fornecer uma excelente solução para a questão de erros da classificação do campo data e hora anulável.

Estou usando o banco de dados SQL Server para o meu projeto.

Alterar o valor nulo de data e hora para '1' resolve o problema de classificação da coluna de tipo de dados de data e hora. No entanto, se tivermos uma coluna com outro tipo de dados datetime, ele falhará no tratamento.

Para lidar com uma classificação de colunas varchar, tentei usar 'ZZZZZZZ', pois sabia que a coluna não tem valores começando com 'Z'. Funcionou como esperado.

Nas mesmas linhas, usei valores máximos +1 para int e outros tipos de dados para obter a classificação conforme o esperado. Isso também me deu os resultados necessários.

No entanto, sempre seria ideal obter algo mais fácil no próprio mecanismo de banco de dados que pudesse fazer algo como:

Order by Col1 Asc Nulls Last, Col2 Asc Nulls First 

Conforme mencionado na resposta fornecida por a_horse_with_no_name.



3

Se você estiver usando o MariaDB, eles mencionam o seguinte na documentação de Valores NULL .

Encomenda

Quando você solicita por um campo que pode conter valores NULL, qualquer NULL é considerado com o menor valor. Portanto, a ordem na ordem DESC verá os NULLs aparecendo por último. Para forçar NULLs a serem considerados como valores mais altos, pode-se adicionar outra coluna que tenha um valor mais alto quando o campo principal for NULL. Exemplo:

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

Ordem decrescente, com NULLs primeiro:

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

Todos os valores NULL também são considerados equivalentes para os propósitos das cláusulas DISTINCT e GROUP BY.

A tabela acima mostra duas maneiras de ordenar por valores NULL. Você também pode combiná-los com as palavras-chave ASC e DESC. Por exemplo, a outra maneira de obter os valores NULL primeiro seria:

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

2

A solução que usa o "caso" é universal, mas não use os índices.

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

No meu caso, eu precisava de desempenho.

 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 você está interessado em desempenho, deveria estar usando UNION ALL.
RedFilter


Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.