Tri sur un champ numerique & la valeur NULL

Pierre01
Invité n'ayant pas de compte PHPfrance

20 déc. 2006, 17:55

Je souhaiterais faire un tri qui peut parraître simple mais que je n'arrive pas à mettre en oeuvre.

J'ai un champ qui contient des valeurs numeriques et la valeur NULL.

Le resultat devrait me retourner ce champ dans un ordre croisant et tous les enregistrements ayant la valeur NULL dans ce champs à la fin.

ex : 1, 6 , 54, 78, NULL, NULL, ...., NULL

"ORDER BY lechamp ASC" me renvoi les valeurs NULL avant les valeurs numeriques c'est à dire au début.

Qqun a une idée pour résoudre mon problème ???

ViPHP
ViPHP | 1961 Messages

20 déc. 2006, 18:11

Bonjour,

Pourquoi ne pas supprimer les champs NULL dans ta requête ?
Deux choses sont infinies, l'Univers et la sottise humaine!!
Mais je ne suis pas sur de ce que j'affirme au sujet de l'Univers.

A. Einstein

Administrateur PHPfrance
Administrateur PHPfrance | 3088 Messages

20 déc. 2006, 18:14

En général, ce genre de problèmes est symptomatique d'un problème d'organisation des données, mais voici quand même une astuce pour obtenir le tri que tu recherches.

En premier, il te faut ajouter une colonne dans la partie "SELECT" représentant 0 ou 1 selon que la colonne utilisée pour le tri est NULL ou non, et utiliser la valeur de cette colonne en premier critère de tri. Par exemple:

Code : Tout sélectionner

SELECT id, nom, prenom, machin, CASE machin WHEN NULL THEN 1 ELSE 0 END AS is_null FROM table ORDER BY is_null ASC, machin ASC
Je te laisse le soin de te documenter sur "CASE" si tu ne connais pas cet opérateur ;)

Pierre01
Invité n'ayant pas de compte PHPfrance

20 déc. 2006, 22:27

Merci pour vos réponse,

Pourquoi ne pas supprimer les champs NULL dans ta requête ?
J'affecte cette valeur NULL par defaut lorsque je n'ai aucun renseignement pour ce champ (dans mon cas il s'agit de stocker des quantitées.)

Comme il s'agit d'un champ numérique j'avais soit le choix entre 0 ou NULL par defaut. Donc je retrouve forcément l'une des deux valeurs citées.

A moi d'en tenir compte dans la suite du traitement.

Ce genre de problèmes est symptomatique d'un problème d'organisation des données
Existerait il une meilleure solution ?

Dans mon cas c'est une table qui contient un champ avec le nom de l'article et un second champ contenant la quantité.
Or pour certains articles je ne peut connaitre leur quantité dans un premier temps pour diverse raison.

La valeur 0 pourrait etre fausse et ainsi poser des problèmes par la suite.

Alors que faut il réorganiser ??

Bon, pour revenir à la question il fallait que je puisse lister tous les articles en fonction de leur quantité et dans un ordre croissant.

J'ai découvert la fonction IFNULL de mysql, qui a permit de resoudre mon problème. Celle ci me permet d'affecter une valeur positive tres élevée de mon choix dans le cas d'un "NULL" et donc de pouvoir retrouver à la fin du jeu d'enregistremnt tous ceux ayant pour valeur NULL dans le champ concertant la quantité.

Donc probléme résolu. :lol:

ViPHP
ViPHP | 1961 Messages

20 déc. 2006, 22:32

Re,
Ce que je voulai dire c'est dans la clause WHERE d'ajouter nom_champ IS NOT NULL.
De cette manière ils n'apparaissent pas dans ton tri.
Deux choses sont infinies, l'Univers et la sottise humaine!!
Mais je ne suis pas sur de ce que j'affirme au sujet de l'Univers.

A. Einstein

Administrateur PHPfrance
Administrateur PHPfrance | 3088 Messages

20 déc. 2006, 23:02

Existerait il une meilleure solution ?
Ça dépend des cas. Il existe toujours une "meilleure" solution mais elle est différente selon les cas et son utilité est très variable. Certaines personnes abhorrent NULL pour des raisons idéologique, mais pour le commun des mortels il y a des cas où ce n'est pas plus mal.

Au niveau des alternative, le plus courant est de supprimer la colonne de la table et de créer une nouvelle table contenant la valeur de la colonne pour les enregistrements qui possèdent une valeur. Dans ton cas, tu aurais une table "quantite" dont les colonnes seraient "produit_id, quantite" et qui ne contiendraient que les numéros et quantités des produits quantifiables. Mais bon, ça complique un petit peu les choses au moment de l'insertion ou la suppression des enregistrements, donc même si ce n'est pas une pratique que je recommande je comprends qu'on utilise NULL.

Même si je n'ai pas d'exemples qui me vient immédiatement à l'esprit, il existe d'autres cas où cesser d'utiliser un champ NULL (et créer une table supplémentaire comme dans l'exemple précité) règle plusieurs problèmes à la fois et rendent les requêtes plus performantes. Ça dépend vraiment des circonstances.
Alors que faut il réorganiser ??
Pour l'instant je dirais non, mais si tu te reposes la question dans quelques jours alors la réponse était peut-être "oui" :P
J'ai découvert la fonction IFNULL de mysql, qui a permit de resoudre mon problème.
Attention à ne pas devenir dépendant des fonctions de MySQL. La requête que j'ai posté plus haut fonctionne sous tous les serveurs SQL, que ce soit n'importe quelle version de MySQL ou PostgreSQL, Oracle, DB2, etc...
Celle ci me permet d'affecter une valeur positive tres élevée de mon choix dans le cas d'un "NULL" [...]
En général ce genre de solution réserve des surprises à long terme. Si tu veux que les NULL soient en dernier, fais en sorte que les NULL soient en dernier. Ne fais pas en sorte que NULL soit égal à 999 parce qu'un jour tu auras peut-être un lot de 1000 petites cuillères dans ta base de données qui va tout envoyer en l'air. Dans le même genre, il se peut que la valeur "arbitrairement haute" que tu as choisi pour représenter NULL devienne tronquée pour des raisons internes qu'il me serait trop long de détailler. L'important, ce qui est à garder à l'esprit, c'est d'aller directement vers ce que l'on recherche. Dès qu'on commence à emprunter des chemins détournés et à deviser des alternatives, on s'expose à des circonstances imprévues et c'est également signe que quelque chose ne va pas.

Mon conseil, essaie la requête que j'ai posté plus haut, et si ça marche utilise ça plutôt qu'une solution qui risque de te péter à la gueule un de ces jours. Et si ça ne marche pas, met à jour le topic, parce qu'elle est sensée marcher.

Pierre01
Invité n'ayant pas de compte PHPfrance

21 déc. 2006, 10:42

Ok Hubert,

Entierement d'accord avec toi.

Effectivement, je reconnais que ma methode n'est pas fiable dans tous les cas. Mais je me doute bien que "la valeur positive tres élevée" ne sera jamais atteinte. :) Si c'etait le cas bah.....mais il va se passer un certain temps avant.

Je vais reprendre tous ca et voir avec ta methode même si la mienne fonctionne dans l'immediat.

Aller au boulot... @++
Pierre

Wrokynet
Invité n'ayant pas de compte PHPfrance

24 mars 2011, 11:15

J'ai également été confronté à ce problème.

J'ai trouvé une solution qui à ces limites mais qui peut bien aider dans certains cas.

select * from table order by case when Champ1 IS NULL then 99999 else 1 end, Champ1 ASC