Aller au contenu

[Resolu] SQL Oracle - Tri alphanumérique


sarx

Messages recommandés

Bonjour,

Je me permet de vous soumettre un petit problème de tri sous Oracle (10g).

J'ai une table dont la description est la suivante :

Code_Art Varchar2(8 ),
Taille   Varchar2(5),
Delai    Date,
Qte      Number

Le contenu de la table peut être le suivant :

Code_Art	Taill	Delai		Qte
--------	-----	--------	-----
J0001		1	<null>		4
J0001		1	10/10/10	1
J0001		1	11/10/10	5
J0001		2	10/10/10	2
J0001		17	10/10/10	3
J0002		UNI	12/10/10	2
...

Le but est de ressortir le contenu en triant sur le code_art, la taille et le delai (avec les null en premier), et d'obtenir le résultat listé au dessus.

Premier essaie de requete :

SELECT *

FROM MATABLE

ORDER BY Code_Art asc, Taille asc, Delai asc NULLS FIRST;

le résultat n'est pas probrant, le tri sur la taille n'est pas celui esperé (mais compréhensible) :

Code_Art	Taill	Delai		Qte
--------	-----	--------	-----
J0001		1	<null>		4
J0001		1	10/10/10	1
J0001		1	11/10/10	5
J0001		17	10/10/10	3
J0001		2	10/10/10	2
J0002		UNI	12/10/10	2
...

Le problème est qu'elle retourne la ligne pour la taille = 17 avant la ligne avec la taille = 2. Jusqu'ici ca reste compréhensible vu qu'il s'agit de caractères.

J'ai essayé de modifier ma requete en utilisant nlssort, mais pas moyen d'obtenir le résultat voulu.

J'ai parcouru different forum et la knowledge database d'oracle, mais il semblerais que je sois le seul a vouloir faire un tri alphanumérique capable de trier correctement les nombres...

Quelqu'un pourrait t'il m'éclairé sur ce probleme ou m'indiquer un début de solution ?

Lien vers le commentaire
Partager sur d’autres sites

Je pense qu'il y a au moins deux solutions à ton problème:

  • Modifier la structure de la table : tu séparerais ton champ 'Taille' en deux champ, un pour stocker les valeurs numérique, un ou plusieurs autres pour les valeurs de type chaîne de caractères (si 'UNI' est la seule chaîne de caractère utilisée, on peut tout à fait plutôt utiliser une valeur booléenne). C'est une modification relativement mineure, et qui ne devrait pas poser de problème si tu as le droit de modifier la structure de la table et qu'il n'y a pas 250 applications à déjà l'utiliser. :francais:
  • Requête de barbare : je suis moins convaincu par la seconde solution que je te propose, étant donné qu'elle devrait, à mon avis, avoir des performances médiocre comparée à l'autre. Il s'agit là encore de séparer les enregistrements où taille s'apparente à une valeur numérique des autres enregistrements. Un regex simple dans la clause WHERE des deux requêtes devrait faire l'affaire. Le résultat des deux requêtes est obtenu en faisant une union. Par contre il faut qu'Oracle soit capable de gérer les CAST dans la clause ORDER BY. Bref, cette solution serait celle de secours si la première n'est pas applicable, mais comme je l'ai dit plus tôt elle risque de nuire à l'efficacité de ton code, ainsi qu'être plus difficilement maintenable derrière.

Lien vers le commentaire
Partager sur d’autres sites

Merci pour les réponses.

Modifier la structure de la table : tu séparerais ton champ 'Taille' en deux champ, un pour stocker les valeurs numérique, un ou plusieurs autres pour les valeurs de type chaîne de caractères (si 'UNI' est la seule chaîne de caractère utilisée, on peut tout à fait plutôt utiliser une valeur booléenne). C'est une modification relativement mineure, et qui ne devrait pas poser de problème si tu as le droit de modifier la structure de la table et qu'il n'y a pas 250 applications à déjà l'utiliser. :francais:

Le problème est que la structure de la table n'est pas vraiment modifiable. La requête doit être utilisé dans le cadre d'une EDI pour l'echange de données entre deux ERP.

La table sur laquelle se base la requete est effectivement modifiable (table de travail), mais le problème de séparation nombre/chain se posera en amont, sur des tables qui sont absolument pas modifiable ^^

Requête de barbare : je suis moins convaincu par la seconde solution que je te propose, étant donné qu'elle devrait, à mon avis, avoir des performances médiocre comparée à l'autre. Il s'agit là encore de séparer les enregistrements où taille s'apparente à une valeur numérique des autres enregistrements. Un regex simple dans la clause WHERE des deux requêtes devrait faire l'affaire. Le résultat des deux requêtes est obtenu en faisant une union. Par contre il faut qu'Oracle soit capable de gérer les CAST dans la clause ORDER BY. Bref, cette solution serait celle de secours si la première n'est pas applicable, mais comme je l'ai dit plus tôt elle risque de nuire à l'efficacité de ton code, ainsi qu'être plus difficilement maintenable derrière.

J'avais effectivement mis en place une requête de ce style, mais vu le coté barbare et complexe de mettre une regexp dans un case dans un nlssort dans un order by... :chinois:

Bref j'espérais que quelqu'un ai une solution un peu plus simple :)

sinon, sous oracle/plsql, t'as cast() qui permet - comme son nom l'indique - de caster

plus d'infos

tu peux le rajouter à l'ORDER BY, il reste plus qu'à gérer les "UNI", et éventuelles autres chaines alphabétiques

Le problème est que pour d'obscures raisons (j'aime les bases avec des données totalement foireuses), il y a un nombre important de chaines de caractères différentes, et que du coup ca commence a devenir presque ingérable.

Je passe tout de même le sujet en résolu, j'ai réussi a trouver une solution de contournement, a défaut d'utiliser la requete barbare.

PI la requête un poil barbare :

SELECT code_art, taille, delai, quantite
FROM matable
ORDER BY code_art ASC, nlssort(
CASE
WHEN regexp_like(taille, '^(\d+)$', 'i') THEN lpad(taille, 5, '0')
ELSE taille
END, 'NLS_SORT=BINARY') ASC, delai ASC nulls FIRST;

Lien vers le commentaire
Partager sur d’autres sites

Archivé

Ce sujet est désormais archivé et ne peut plus recevoir de nouvelles réponses.

×
×
  • Créer...