Pourquoi est-ce que lorsque nous avons une valeur NULL dans une colonne et que nous classons par valeur croissante, les NULL sont triés en premier?
select 1 as test
union all
select 2
union all
select NULL
union all
select 3
union all
select 4
order by test
résulte en
NULL
1
2
3
4
Je continue de penser que NULL signifiait "Indéterminant" ou possible "Inconnu". Si c'est vrai, ne trieraient-ils pas en dernier, car la valeur pourrait être supérieure à toutes les autres valeurs? (Ou est-ce une option de tri quelque part?)
Je suis sur SQL Server 2008R2, mais je soupçonne que cela est vrai sur tous les serveurs SQL, et probablement sur tous les SGBDR.
BOL : Une valeur NULL indique que la valeur est inconnue. Une valeur NULL est différente d'une valeur vide ou nulle. Il n'y a pas deux valeurs nulles égales. Les comparaisons entre deux valeurs nulles ou entre une valeur NULL et toute autre valeur retournent inconnue car la valeur de chaque valeur NULL est inconnue.
NULL signifie inconnu. Aucune autre interprétation n'est valable.
Si c'est vrai, ne trieraient-ils pas en dernier, car la valeur pourrait être supérieure à toutes les autres valeurs?
Il n'y a pas pourrait être . Il n'y a pas de valeur potentielle . Inconnu est inconnu est inconnu.
Quant à savoir pourquoi il apparaît en premier, plutôt qu'en dernier, cela n'est pas pris en charge par les normes SQL publiées et est malheureusement laissé à la discrétion du fournisseur du SGBDR:
Wikipedia : Le standard SQL ne définit pas explicitement un ordre de tri par défaut pour Nulls. Au lieu de cela, sur les systèmes conformes, les valeurs Null peuvent être triées avant ou après toutes les valeurs de données en utilisant respectivement les clauses NULLS FIRST ou NULLS LAST de la liste ORDER BY. Cependant, tous les fournisseurs de SGBD n'implémentent pas cette fonctionnalité. Les fournisseurs qui n'implémentent pas cette fonctionnalité peuvent spécifier des traitements différents pour le tri nul dans le SGBD.
Vous avez raison de dire que NULL
peut signifier "Indéterminant" ou "Uknownn" ou "Pas encore connu" ou "Ne pas appliquer". Mais il n'y a aucune raison de placer les Nulls en premier ou en dernier. Si nous ne connaissons pas les valeurs réelles, alors ils peuvent être petits ou grands.
Je pense que la norme pour déterminer le comportement souhaité des Nulls pendant le tri est:
ORDER BY
test NULLS LAST --- or NULLS FIRST for the opposite
Malheureusement, SQL-Server n'a pas encore adopté cette syntaxe. Si je ne me trompe pas, PostgreSQL et Oracle l'ont.
Une solution:
ORDER BY
CASE WHEN test IS NOT NULL
THEN 0
ELSE 1
END
, test
Une autre solution qui doit être ajustée en fonction du type de données - mais qui ne fonctionnera pas bien, car elle ne peut pas utiliser d'index sur (test)
:
ORDER BY
COALESCE(test, 2147483647) --- if it's a 4-byte signed integer
Je ne sais pas pourquoi c'est fait de cette façon, mais par définition, NULLS ne peut pas être comparé à des non-NULLS, donc ils doivent aller au début ou à la fin (la réponse de Mark couvre cela dans beaucoup plus de détails).
Pour obtenir le comportement que vous souhaitez - Pour autant que je sache, il n'y a pas d'option de tri pour mettre les valeurs nulles en dernier, vous devez donc les héberger en utilisant une colonne calculée pour les forcer en dernier. Cependant, dans SQL Server, vous ne pouvez pas trier par une colonne calculée (CASE WHEN ...
) lorsque vos données contiennent un opérateur d'ensemble (UNION ALL
). Donc:
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
Fonctionne pour le tri des valeurs nulles en dernier. Si vous devez utiliser UNION
(ou EXCEPT
ou INTERSECTS
) pour générer votre ensemble de données, puis videz vos données dans une table temporaire comme ci-dessus.
Si vous avez affaire à des chiffres, vous pouvez également utiliser
ORDER BY -test DESC
NULL
sont les valeurs les plus basses possibles, donc DESC
les met à la fin. Pendant ce temps, les valeurs non nulles ont le signe inversé, donc DESC
est en fait un ASC
sur les valeurs réelles. Cela devrait être plus rapide que CASE
et je suppose que l'optimiseur de requête peut également utiliser des index sur la colonne test
.