SQL Server ORDER BY fecha y últimos nulos


82

Estoy intentando ordenar por fecha. Quiero que las fechas más recientes aparezcan primero. Eso es bastante fácil, pero hay muchos registros que son nulos y vienen antes de cualquier registro que tenga una fecha.

He intentado algunas cosas sin éxito:

ORDER BY ISNULL(Next_Contact_Date, 0)

ORDER BY ISNULL(Next_Contact_Date, 999999999)

ORDER BY coalesce(Next_Contact_Date, 99/99/9999)

¿Cómo puedo ordenar por fecha y que los nulos sean los últimos? El tipo de datos es smalldatetime.


¿El orden de clasificación debe ser Ascendente, pero con nulos al final? ¿Y tendrás fechas futuras en tu mesa?
AllenG

@AllenG, sí, del pasado al futuro con el pasado primero y así sucesivamente. Así que sí, ascendiendo. Sí, las fechas futuras son las que serán la mayoría de ellas.
UpHelix

Respuestas:


112

smalldatetime tiene un rango hasta el 6 de junio de 2079, por lo que puede usar

ORDER BY ISNULL(Next_Contact_Date, '2079-06-05T23:59:00')

Si no hay registros legítimos tendrá esa fecha.

Si esta no es una suposición, le gustaría confiar en una opción más sólida: ordenar en dos columnas.

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

Sin embargo, ambas sugerencias anteriores no pueden utilizar un índice para evitar una clasificación y ofrecen planes de apariencia similar.

ingrese la descripción de la imagen aquí

Otra posibilidad si existe tal índice es

SELECT 1 AS Grp, Next_Contact_Date 
FROM T 
WHERE Next_Contact_Date IS NOT NULL
UNION ALL
SELECT 2 AS Grp, Next_Contact_Date 
FROM T 
WHERE Next_Contact_Date IS NULL
ORDER BY Grp, Next_Contact_Date

Plan


Este truco también se puede aplicar a los VARCHARcampos (p ORDER BY ISNULL(my_varchar, 'ZZZZZZ'). Ej. ) Y es extremadamente útil, especialmente para obtener pedidos de cierta manera cuando se usa GROUP BY . . . GROUPING SETS. Gracias por publicar esto.
sparc_spread

¿Por qué no podemos usar order by desc para poner nulos en la parte inferior? además, ¿por qué asignamos nulo a 1?
MasterJoe

35

Según Itzik Ben-Gan, autor de T-SQL Fundamentals para MS SQL Server 2012 , "De forma predeterminada, SQL Server ordena las marcas NULL antes que los valores no NULL . Para que las marcas NULL clasifiquen en último lugar, puede usar una expresión CASE que devuelva 1 cuando la columna " Next_Contact_Date es NULL " y 0 cuando no es NULL . Las marcas que no son NULL obtienen 0 de la expresión; por lo tanto, se clasifican antes que las marcas NULL (que obtienen 1). Esta expresión CASE se usa como la primera ordenar columna ". el Next_Contact_Datecolumn "debe especificarse como la segunda columna de clasificación. De esta forma, las marcas que no son NULL se clasifican correctamente entre sí". Aquí está la consulta de solución para su ejemplo para MS SQL Server 2012 (y SQL Server 2014):

ORDER BY 
   CASE 
        WHEN Next_Contact_Date IS NULL THEN 1
        ELSE 0
   END, Next_Contact_Date;

Código equivalente con sintaxis IIF:

ORDER BY 
   IIF(Next_Contact_Date IS NULL, 1, 0),
   Next_Contact_Date;

Además, para agregar a la respuesta, si cambia el 1 y el 0 del IIF, los nulos irán a la parte superior. Esto también funciona si desea una tupla única colocándolas en la parte superior de la mesa.
Franco Pettigrosso

3

Si su SQL no admite NULLS FIRSTo NULLS LAST, la forma más sencilla de hacer esto es usar la value IS NULLexpresión:

ORDER BY Next_Contact_Date IS NULL, Next_Contact_Date

para poner los nulos al final ( NULLS LAST) o

ORDER BY Next_Contact_Date IS NOT NULL, Next_Contact_Date

para poner los nulos al frente. Esto no requiere conocer el tipo de columna y es más fácil de leer que la CASEexpresión.

EDITAR: Por desgracia, aunque esto funciona en otras implementaciones de SQL como PostgreSQL y MySQL, no funciona en MS SQL Server. No tenía un servidor SQL para probar y confié en la documentación y las pruebas de Microsoft con otras implementaciones de SQL. Según Microsoft, value IS NULL es una expresión que debería ser utilizable como cualquier otra expresión. Y ORDER BY se supone que toma expresiones como cualquier otra declaración que toma una expresión. Pero en realidad no funciona.

Por tanto, la mejor solución para SQL Server parece ser la CASEexpresión.


7
Esta no es una sintaxis válida de SQL Server
Martin Smith

3
Lo siento por eso. Se debe ser válido por la documentación y obras en otros LSQ Microsoft, pero MS en realidad no lo permiten.
Vroo

En cuanto al rendimiento, esto suena terrible, estás haciendo 2 criterios de clasificación
ColacX

En la documentación de Microsoft que vinculó, leí que el valor IS NULL no es una expresión , sino un predicado . No es lo mismo.
BertuPG

1
Según Microsoft, un predicado es una expresión. Esas son literalmente las primeras tres palabras en docs.microsoft.com/en-us/sql/t-sql/queries/predicates
Vroo

3
order by -cast([Next_Contact_Date] as bigint) desc

arrojar un error si Next_Contact_Datees nuloExplicit conversion from data type date to bigint is not allowed.
Nerdroid

2

Un poco tarde, pero tal vez alguien lo encuentre útil.

Para mí, ISNULL estaba fuera de discusión debido al escaneo de la tabla. UNION ALL necesitaría que repitiera una consulta compleja, y debido a que seleccioné solo el TOP X, no habría sido muy eficiente.

Si puede cambiar el diseño de la mesa, puede:

  1. Agregue otro campo, solo para ordenar, como Next_Contact_Date_Sort.

  2. Cree un disparador que llene ese campo con un valor grande (o pequeño), según lo que necesite:

    CREATE TRIGGER FILL_SORTABLE_DATE ON YOUR_TABLE AFTER INSERT,UPDATE AS 
    BEGIN
        SET NOCOUNT ON;
        IF (update(Next_Contact_Date)) BEGIN
        UPDATE YOUR_TABLE SET Next_Contact_Date_Sort=IIF(YOUR_TABLE.Next_Contact_Date IS NULL, 99/99/9999, YOUR_TABLE.Next_Contact_Date_Sort) FROM inserted i WHERE YOUR_TABLE.key1=i.key1 AND YOUR_TABLE.key2=i.key2
        END
    END
    

2

Use desc y multiplique por -1 si es necesario. Ejemplo de orden int ascendente con nulos al final:

select * 
from
(select null v union all select 1 v union all select 2 v) t
order by -t.v desc

No creo que esto funcione para fechas variables como ...
Charlotte Deng

1

Sé que esto es viejo pero esto es lo que funcionó para mí

Order by Isnull(Date,'12/31/9999')
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.