web-dev-qa-db-fra.com

SQL Server ORDER BY date et NULL en dernier

J'essaie de commander par date. Je veux les dates les plus récentes à venir en premier. C'est assez facile, mais de nombreux enregistrements sont nuls et viennent avant ceux ayant une date.

J'ai essayé quelques choses sans succès:

ORDER BY ISNULL(Next_Contact_Date, 0)

ORDER BY ISNULL(Next_Contact_Date, 999999999)

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

Comment puis-je commander par date et faire en sorte que les valeurs NULL arrivent en dernier? Le type de données est smalldatetime.

62
UpHelix

smalldatetime va jusqu'au 6 juin 2079 pour que vous puissiez utiliser

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

Si aucun enregistrement légitime n'aura cette date.

S'il ne s'agit pas d'une hypothèse, il est préférable de trier sur deux colonnes une option plus robuste. 

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

Les deux suggestions ci-dessus ne permettent pas d'utiliser un index pour éviter un tri et donner des plans similaires. 

enter image description here

Une autre possibilité si un tel index existe est

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

89
Martin Smith

Selon Itzik Ben-Gan, auteur de Principes de base de T-SQL pour MS SQL Server 2012, "Par défaut, SQL Server trieNULLmarques avant non -NULLvaleurs. Pour obtenirNULLmarques à trier en dernier, vous pouvez utiliser une expressionCASEqui retourne 1 lorsque "Next_Contact_Datecolumn estNULL, "et 0 ​​s'il ne l'est pasNULL. Non -NULLLes marques récupèrent 0 de l’expression et sont donc triées avantNULLmarques (qui obtiennent 1). Cette expressionCASEest utilisée comme la première colonne de tri. " La colonneNext_Contact_Date"doit être spécifiée comme deuxième colonne de tri. De cette manière, les marques non -NULLsont correctement triées entre elles." Voici la requête de solution pour votre exemple pour MS SQL Server 2012 (et SQL Server 2014): 

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

Code équivalent utilisant la syntaxe IIF:

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

Un peu tard, mais peut-être que quelqu'un trouvera cela utile. 

Pour moi, ISNULL était hors de question en raison de l'analyse de la table. UNION ALL aurait besoin de moi pour répéter une requête complexe, et comme je n'avais sélectionné que le TOP X, cela n'aurait pas été très efficace.

Si vous pouvez modifier la conception de la table, vous pouvez:

  1. Ajoutez un autre champ, uniquement pour le tri, tel que Next_Contact_Date_Sort.

  2. Créez un déclencheur qui remplit ce champ avec une grande (ou petite) valeur, selon vos besoins:

    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
Aaa
order by -cast([Next_Contact_Date] as bigint) desc
2
paparazzo

Si votre code SQL ne prend pas en charge NULLS FIRST ou NULLS LAST, le moyen le plus simple consiste à utiliser l'expression value IS NULL:

ORDER BY Next_Contact_Date IS NULL, Next_Contact_Date

mettre les valeurs nuls à la fin (NULLS LAST) ou 

ORDER BY Next_Contact_Date IS NOT NULL, Next_Contact_Date

mettre les nuls à l'avant. Cela n'exige pas de connaître le type de la colonne et est plus facile à lire que l'expression CASE.

EDIT: Hélas, bien que cela fonctionne dans d'autres implémentations SQL telles que PostgreSQL et MySQL, cela ne fonctionne pas dans MS SQL Server. Je n'avais pas de serveur SQL sur lequel tester et je m'appuyais sur la documentation de Microsoft et sur des tests avec d'autres implémentations SQL. Selon Microsoft, value IS NULLest une expression qui devrait être utilisable comme toute autre expression. Et ORDER BYest supposé prendre des expressions comme toute autre déclaration qui prend une expression. Mais ça ne marche pas vraiment.

La meilleure solution pour SQL Server semble donc être l'expression CASE.

1
Vroo

Utilisez desc et multipliez par -1 si nécessaire. Exemple de classement int croissant avec les valeurs NULL en dernier:

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

Je sais que c'est vieux mais c'est ce qui a fonctionné pour moi

Order by Isnull(Date,'12/31/9999')
0
anonymous