MySQL Orderby a number, Nulls last

280

Actuellement, je fais un OrderBy très basique dans ma déclaration.

SELECT * FROM tablename WHERE visible=1 ORDER BY position ASC, id DESC

Le problème avec ceci est que les entrées NULL pour 'position' sont traitées comme 0. Par conséquent, toutes les entrées avec position comme NULL apparaissent avant celles avec 1,2,3,4. par exemple:

NULL, NULL, NULL, 1, 2, 3, 4

Existe-t-il un moyen d'obtenir l'ordre suivant:

1, 2, 3, 4, NULL, NULL, NULL.
JonB
la source
8
Vous devriez reconsidérer la réponse de user1052645. C'est plus simple, ne nécessite aucune connaissance des valeurs maximales et pourrait être plus rapide (en supposant que l'évaluation d'une expression peut être plus rapide qu'un appel de fonction).
Steve Clay

Réponses:

568

MySQL a une syntaxe non documentée pour trier les null en dernier. Placez un signe moins (-) avant le nom de la colonne et passez l'ASC à DESC:

SELECT * FROM tablename WHERE visible=1 ORDER BY -position DESC, id DESC

C'est essentiellement l'inverse de position DESCplacer les valeurs NULL en dernier mais sinon les mêmes que position ASC.

Une bonne référence est ici http://troels.arvin.dk/db/rdbms#select-order_by

Jarred
la source
79
Ce n'est pas non documenté, - col_namec'est une expression ( 0 - col_name), que la clause ORDER BY accepte. Bien sûr, cela ne fonctionne que pour les colonnes numériques.
Steve Clay
7
Joli. Works pour dateet timecolonnes aussi! (MySQL 5.5). Je suppose (je suis paresseux de vérifier) ​​que cela fonctionne pour toutes les colonnes de type numérique (horodatage, float ...).
Martin
6
@koral: c'est une expression mathématique simple (et utile) qui inverse l'ordre, elle ne sera supprimée que si la langue elle-même change radicalement.
Bell
11
Comme le suggèrent les commentaires, cela fonctionne-t-il pour les colonnes numériques, de date et d'heure? Mais qu'en est-il de varchar? Peut-il également être appliqué pour varchar? J'ai essayé de l'appliquer aux champs varchar, mais l'ordre semble différent de celui de l'utilisation de l'ASC ou du DESC.
Sumit Desai
9
Cela n'empêchera-t-il pas l'utilisation d'un index possible sur la colonne de commande?
Tarsis
306

J'ai trouvé que c'était une bonne solution pour la plupart:

SELECT * FROM table ORDER BY ISNULL(field), field ASC;
d -_- b
la source
6
Sans redéfinir l'ordre des travaux: SELECT * FROM table ORDER BY ISNULL(field) ASC;(MySQL 5.5)
Marçal Juan
5
C'est une meilleure solution.
Rok Kralj
4
La solution acceptée ne fonctionne pas avec TIMESTAMP dans postgresql 9.3. Cette solution ne ...
kalu
2
De façon ennuyeuse, MySQL n'utilisera pas d'index sur le champ lorsque vous ajoutez isnull (champ) à la clause order by (lors de l'utilisation de limit).
Barry Kelly
3
@kalu: Dans PostgreSQL , les valeurs NULL sont triées en dernier dans l'ordre croissant (et en premier dans l'ordre décroissant). Et vous préférez utiliser la clause SQL standardNULLS LAST | NULLS FIRSTpour le retourner au lieu des solutions de contournement ici.
Erwin Brandstetter du
23

Quelque chose comme

SELECT * FROM tablename where visible=1 ORDER BY COALESCE(position, 999999999) ASC, id DESC

Remplacez 999999999 par la valeur maximale du champ

DrewM
la source
3
Cette solution est fragile et peut conduire à des bugs intermittents
Dmitry Bogdanovich
20

NULL DERNIER

SELECT * FROM table_name ORDER BY id IS NULL, id ASC
sumeet
la source
4

Vous pouvez échanger des instances de NULL avec une valeur différente pour les trier en premier (comme 0 ou -1) ou en dernier (un grand nombre ou une lettre) ...

SELECT field1, IF(field2 IS NULL, 9999, field2) as ordered_field2
  FROM tablename
 WHERE visible = 1
 ORDER BY ordered_field2 ASC, id DESC
Langdon
la source
Cela ne résoudra pas le problème car l'index référencé dans ORDER BY ne sera pas affecté par le remplacement des valeurs dans l'instruction SELECT et ne corrigera donc pas l'ordre. Consultez également la fonction COALESCE, qui est fonctionnellement équivalente à votre utilisation de la fonction IF.
définit le
Si vous alias l'instruction IF correctement, les lignes sont ordonnées comme vous vous y attendez. J'ai corrigé mon exemple.
Langdon
4

Essayez d'utiliser cette requête:

SELECT * FROM tablename
WHERE visible=1 
ORDER BY 
CASE WHEN position IS NULL THEN 1 ELSE 0 END ASC,id DESC
Rachit Patel
la source
Pas besoin d'étui. IS NULL renvoie 1 lorsque l'expression est NULL. Voir la réponse de reverbnation.
contactmatt
3

Vous pouvez fusionner vos NULLs dans l' ORDER BYinstruction:

select * from tablename
where <conditions>
order by
    coalesce(position, 0) ASC, 
    id DESC

Si vous souhaitez que les valeurs NULL soient triées en bas, essayez coalesce(position, 100000). (Faites le deuxième nombre plus grand que tous les autres positiondans la base de données.)

Seth
la source
3
SELECT * FROM tablename WHERE visible=1 ORDER BY CASE WHEN `position` = 0 THEN 'a' END , position ASC
YasirPoongadan
la source
6
Pourquoi le PO devrait-il essayer cela ? Les bonnes réponses auront toujours une explication de ce qui a été fait et pourquoi cela a été fait de cette façon, non seulement pour le PO mais pour les futurs visiteurs de SO qui peuvent trouver cette question et lire votre réponse.
RiggsFolly
2

Pour une DATEcolonne, vous pouvez utiliser:


NULLS last:

ORDER BY IFNULL(`myDate`, '9999-12-31') ASC

Les blancs durent:

ORDER BY IF(`myDate` = '', '9999-12-31', `myDate`) ASC
Danny Beckett
la source
1

Pour obtenir le résultat suivant:

1, 2, 3, 4, NULL, NULL, NULL.

UTILISER la syntaxe, placer -(minus sign)avant le nom du champ et utiliser le type_ordre inverse (comme: si vous voulez commander par ordre ASC, utilisez DESC ou si vous voulez commander DESC, utilisez ASC)

SELECT * FROM tablename WHERE visible=1 ORDER BY -position DESC

Nishu Garg
la source
1

Cela fonctionne bien:

SELECT * FROM tablename ORDER BY position = 0, position ASC;

position
1 
2
3
0
0
voxl.de
la source
-8

Pourquoi ne commandez-vous pas par NULLS DERNIER?

SELECT * 
FROM tablename
WHERE visible = 1 
ORDER BY position ASC NULLS LAST, id DESC 
RedRover
la source
NULLS LAST- quelle version de MySQL a été introduite?
crmpicco
2
@Panique, vous voulez dire (MS) SQL Server?
d -_- b
1
cette réponse ne s'applique pas à MySQL
PeppyHeppy