SQL cómo hacer que los valores nulos lleguen al final cuando se ordena de forma ascendente

297

Tengo una tabla SQL con un campo de fecha y hora. El campo en cuestión puede ser nulo. Tengo una consulta y quiero que los resultados se ordenen de manera ascendente por el campo de fecha y hora, sin embargo, quiero filas donde el campo de fecha y hora sea nulo al final de la lista, no al principio.

¿Hay una manera simple de lograr eso?

David Božjak
fuente

Respuestas:

394
select MyDate
from MyTable
order by case when MyDate is null then 1 else 0 end, MyDate
RedFilter
fuente
2
Sin embargo, tenga en cuenta que si coloca un índice en la columna de clasificación para mejorar el rendimiento (*), este método complicará un poco el plan de consulta y perderá gran parte del beneficio de rendimiento. * - los índices proporcionaron los datos preseleccionados, evitando así una clasificación por ejecución de consulta. Es posible filtrar los registros NULL si es posible para evitar este problema por completo.
redcalx
2
Buena respuesta también dada aquí con todas las formas posibles con ventajas y desventajas nickstips.wordpress.com/2010/09/30/…
sudhAnsu63
40
order by case when MyDate is null then 1 else 0 endes una forma muy larga de decirORDER BY MyDate IS NULL
Martin
55
@ Martin Tenga en cuenta que esta pregunta no está etiquetada mysql. Proporcioné una solución generalizada: hay muchas formas diferentes de hacer lo mismo en diferentes dbs.
RedFilter
1
@KyleDelaney Debido a que order by 0se interpreta como un índice de columna, y los índices de columna se basan en 1. Para ordenar una consulta por la tercera columna, puede decir order by 3(que es una idea terrible para las consultas de producción), pero muy útil (como está *) al experimentar.
RedFilter
159

(Un "poco" tarde, pero esto no se ha mencionado en absoluto)

No especificó su DBMS.

En SQL estándar (y el DBMS más moderno como Oracle, PostgreSQL, DB2, Firebird, Apache Derby, HSQLDB y H2) puede especificar NULLS LASTo NULLS FIRST:

Use NULLS LASTpara ordenarlos hasta el final:

select *
from some_table
order by some_column DESC NULLS LAST
un caballo sin nombre
fuente
16
AFAIK NULLS FIRSTy NULLS LASTse han agregado en SQL: 2003, pero no hay una implementación estándar disponible en los diferentes DMBS '. Dependiendo del motor de la base de datos, use 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 una implementación ISNULL () diferente).
SaschaM78
3
@ SaschaM78: la clasificación predeterminada de NULL depende de DBMS. Algunos los clasifican al final, otros al principio. Algunos no se preocupan por ASC/ DESCcon nulos, algunos sí. Entonces, la única manera de garantizar esto es usarlo NULL FIRST/LAST si el DBMS lo admite. En él documenta lo que pretende. El uso de isnull()u otras funciones es una solución alternativa para la falta de soporte para NULLS FIRST/LAST(que es compatible con Oracle, PostgreSQL, DB2, Firebird, Apache Derby, HSQLDB y H2)
a_horse_with_no_name
Tiene toda la razón, solo quería agregar el hecho de que hay bastantes DBMS que no siguen el estándar (todavía) o tienen sus especialidades como Oracle que requieren la exprpalabra clave cuando se usan NULLS FIRST / LAST. Y gracias por los nulos mostrados primero / último que varían de un tipo de base de datos a otro, ¡no lo sabía!
SaschaM78
2
Esto parece prometedor, pero lamentablemente, lo intenté y NULLS LASTno funcionó en mi base de datos MySQL.
AdmiralThrawn
1
@AdmiralAdama: siempre puedes actualizar a Postgres
a_horse_with_no_name el
35

También me topé con esto y lo siguiente parece ser el truco para mí, en MySQL y PostgreSQL:

ORDER BY date IS NULL, date DESC

tal como se encuentra en https://stackoverflow.com/a/7055259/496209

Luksurious
fuente
Esto parece prometedor, pero lamentablemente, lo probé IS NULLy IS NOT NULLno funcionó en mi base de datos MySQL.
AdmiralThrawn
14
order by coalesce(date-time-field,large date in future)
Gratzy
fuente
10
Si bien esto generalmente funcionará, debe tenerse en cuenta que esta respuesta tiene algunos problemas: una fecha grande en el futuro puede colisionar o ser menor que los datos reales, lo que resulta en un tipo imperfecto. Además, es una solución de "número mágico" que no se documenta automáticamente.
RedFilter
Esto resulta ser una gran alternativa a la respuesta @RedFilter cuando necesita comparar la columna en cuestión con otra columna de fecha. Lo uso para la lista de antigüedad sindical. Si el empleado tiene una fecha calificada (que es anulable), esa fecha se registra en la parte superior; de lo contrario, use HireDate. El uso de ORDER BY ISNULL (QualifiedDate, '1-1-2099'), HireDate, LastName, etc. hace que la fecha calificada no entre en conflicto con la fecha HiredDate y se produzca la lista de senirity correcta.
Alan Fisher
14

Puede usar la función integrada para verificar si es nulo o no, como se muestra a continuación. Lo pruebo y funciona bien.

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

Majdi M. Aburahelah
fuente
Para las fechas para trabajar con mssql, encontré útil poner un lejano en la fecha futura en la función ISNULL, es decir, ISNULL (MyDate, '2100-01-01')
Emi-C
En MySQL, dice que estoy pasando demasiados parámetros. Obtuve esto para analizar haciendo ISNULL(MyDate) DESC, MyDate ASC, pero no se ordenó en el orden correcto.
AdmiralThrawn
12

Si su motor lo permite ORDER BY x IS NULL, xo lo ORDER BY x NULLS LASTusa. Pero si no es así, esto podría ayudar:

Si está ordenando por un tipo numérico, puede hacer esto: (Tomar prestado el esquema de otra respuesta ).

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

resultado que muestra ordenado por DepartmentId con nulos últimos

Cualquier número no nulo se convierte en 0 y los nulos se convierten en 1, lo que clasifica los nulos en último lugar.

También puede hacer esto para cadenas:

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

resultado que muestra ordenado por apellido con nulos últimos

Porque 'a'> ''.

Esto incluso funciona con fechas coaccionando a un int anulable y usando el método para las entradas anteriores:

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

(Supongamos que el esquema tiene HireDate).

Estos métodos evitan el problema de tener que encontrar o administrar un valor "máximo" de cada tipo o solucionar consultas si el tipo de datos (y el máximo) cambia (ambos problemas que sufren otras soluciones ISNULL). Además, son mucho más cortos que un CASO.

infogulch
fuente
Funciona genial ! Gracias
Vani
8

Cuando su columna de orden es numérica (como un rango), puede multiplicarla por -1 y luego ordenarla en orden descendente. Mantendrá el orden que está experimentando, pero ponga NULL al final.

select *
from table
order by -rank desc
Luizgrs
fuente
Estaba a punto de comentar esto. Lo aprendí de stackoverflow.com/a/8174026/1193304 y es genial
Chris
3

Gracias RedFilter por proporcionar una excelente solución al problema de la clasificación de campos de fecha y hora anulables.

Estoy usando la base de datos SQL Server para mi proyecto.

Cambiar el valor nulo de fecha y hora a '1' resuelve el problema de ordenar la columna de tipo de datos de fecha y hora. Sin embargo, si tenemos una columna con otro tipo de datos que no sea datetime, entonces no se puede manejar.

Para manejar una clasificación de columna varchar, intenté usar 'ZZZZZZZ' ya que sabía que la columna no tiene valores que comiencen con 'Z'. Funcionó como se esperaba.

En la misma línea, utilicé valores máximos +1 para int y otros tipos de datos para obtener el orden como se esperaba. Esto también me dio los resultados necesarios.

Sin embargo, siempre sería ideal obtener algo más fácil en el motor de la base de datos que podría hacer algo como:

Order by Col1 Asc Nulls Last, Col2 Asc Nulls First 

Como se menciona en la respuesta proporcionada por a_horse_with_no_name.

Kasim Husaini
fuente
3

En Oracle, puede usar NULLS FIRSTo NULLS LAST: especifica que los valores NULL deben devolverse antes / después de los valores no NULL:

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

Por ejemplo:

ORDER BY date DESC NULLS LAST

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

Joaquinglezsantos
fuente
3

Si está utilizando MariaDB, mencionan lo siguiente en el documentación de valores NULL .

Ordenar

Cuando ordena por un campo que puede contener valores NULL, se considera que cualquier NULL tiene el valor más bajo. Por lo tanto, al realizar el pedido en orden DESC, los NULL aparecerán en último lugar. Para forzar que los NULL se consideren como valores más altos, se puede agregar otra columna que tenga un valor más alto cuando el campo principal es NULL. Ejemplo:

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

Orden descendente, con NULL primero:

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

Todos los valores NULL también se consideran equivalentes a los fines de las cláusulas DISTINCT y GROUP BY.

Lo anterior muestra dos formas de ordenar por valores NULL, también puede combinarlos con las palabras clave ASC y DESC. Por ejemplo, la otra forma de obtener los valores NULL primero sería:

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

La solución que usa el "caso" es universal, pero luego no use los índices.

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

En mi caso, necesitaba rendimiento.

 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
fuente
1
Si está interesado en el rendimiento, debería usarlo UNION ALL.
RedFilter
0
order by -cast([nativeDateModify] as bigint) desc
paparazzo
fuente