57 votes

Comment trier une colonne VARCHAR dans le serveur SQL qui contient des chiffres ?

J'ai un VARCHAR dans une colonne SQL Server 2000 qui peut contenir des lettres ou des chiffres. Cela dépend de la façon dont l'application est configurée sur le front-end pour le client.

Lorsqu'ils contiennent des chiffres, je veux qu'ils soient triés numériquement, par exemple "1", "2", "10" au lieu de "1", "10", "2". Les champs contenant uniquement des lettres, ou des lettres et des chiffres (comme 'A1') peuvent être triés par ordre alphabétique comme d'habitude. Par exemple, voici un ordre de tri acceptable.

1
2
10
A
B
B1

Quelle est la meilleure façon d'y parvenir ?

0 votes

Notez également que IsNumeric renvoie 1 pour les valeurs 24e4 et 12d34

1 votes

Face à ce problème, je suis venu ici. En voyant votre question, j'ai remarqué une hypothèse erronée. Vous avez dit "Les champs contenant uniquement des lettres, ou des lettres et des chiffres (comme 'A1') peuvent être triés par ordre alphabétique comme d'habitude." Essayez d'ordonner A1, A2 et A10. Vous obtiendrez A1, A10, A2. Maintenant que j'ai fini avec la partie question, je vais chercher une réponse ci-dessous. J'espère en trouver une :)

0 votes

@anarkhalilov l'avez-vous fait ?

82voto

Aleris Points 4674

Une solution possible consiste à ajouter un caractère devant les valeurs numériques afin que toutes les chaînes aient la même longueur.

Voici un exemple utilisant cette approche :

select MyColumn
from MyTable
order by 
    case IsNumeric(MyColumn) 
        when 1 then Replicate('0', 100 - Len(MyColumn)) + MyColumn
        else MyColumn
    end

En 100 doit être remplacée par la longueur réelle de cette colonne.

0 votes

J'ai constaté que l'un des champs de notre base de données de test contient 12345678901234567890, ce qui pose des problèmes avec les autres solutions. Certes, il est peu probable que cela se produise dans une base de données client réelle, mais si c'était le cas, cette solution serait capable de le gérer avec succès.

1 votes

J'ai dû changer char(0) en '0' pour que ça marche... sinon c'est solide. Les autres solutions données ici ne fonctionnent pas bien pour le tri descendant s'il y a des nullités dans la table.

0 votes

Char(0) est nul, ce qui fait que le résultat est nul, il faut donc utiliser '0' à la place.

13voto

Cowan Points 17235

Il y a plusieurs façons de procéder.

L'un d'eux serait

SELECT
 ...
ORDER BY
  CASE 
    WHEN ISNUMERIC(value) = 1 THEN CONVERT(INT, value) 
    ELSE 9999999 -- or something huge
  END,
  value

la première partie du ORDER BY convertit tout en int (avec une valeur énorme pour les non-numériques, pour les trier en dernier) puis la dernière partie s'occupe des alphabétiques.

Notez que les performances de cette requête sont probablement au moins modérément épouvantables sur de grandes quantités de données.

0 votes

Les tables sont généralement de simples tables de "référence" et ne comportent pas un grand nombre de lignes (quelques centaines tout au plus, de sorte que les performances ne sont pas un problème majeur).

0 votes

D'après l'article de l'échange d'experts que je mets en lien ici : stackoverflow.com/questions/119730/ Je pense que vous devez convertir en MONEY puis en INT pour éviter que '$' soit lu comme un chiffre.

5voto

Luke Bennett Points 16100
select
  Field1, Field2...
from
  Table1
order by
  isnumeric(Field1) desc,
  case when isnumeric(Field1) = 1 then cast(Field1 as int) else null end,
  Field1

Cela renverra les valeurs dans l'ordre que vous avez indiqué dans votre question.

Les performances ne seront pas très bonnes avec tout ce casting. Une autre approche consiste donc à ajouter une autre colonne à la table dans laquelle vous stockez une copie entière des données, puis à trier d'abord par cette colonne, puis par la colonne en question. Cela nécessitera évidemment quelques modifications de la logique qui insère ou met à jour les données dans la table, afin de remplir les deux colonnes. Vous pouvez aussi placer un déclencheur sur la table pour remplir la deuxième colonne chaque fois que des données sont insérées ou mises à jour.

0 votes

claque la tête C'est le cas ! Enfin, c'est fait... j'ai mis un correctif maintenant. J'ai fait l'erreur classique de bricoler une solution qui fonctionne après l'avoir testée ! Bien vu, merci.

5voto

JohnB Points 6869
SELECT *, CONVERT(int, your_column) AS your_column_int
FROM your_table
ORDER BY your_column_int

OU

SELECT *, CAST(your_column AS int) AS your_column_int
FROM your_table
ORDER BY your_column_int

Les deux sont assez portables, je pense.

0 votes

+1 pour la simplicité et la succinctivité. Contrairement aux autres, c'est super facile à regarder et à comprendre. Ma seule question est de savoir si le tri se ferait toujours dans les cas où les données ne sont pas numériques ?

4 votes

Comme l'a dit l'OP, your_column comprend également les lettres. La solution que vous proposez ne fonctionnera pas pour les valeurs comprenant des lettres.

2voto

Corey Trager Points 11334

Cela semble fonctionner :

select your_column  
from your_table  
order by   
case when isnumeric(your_column) = 1 then your_column else 999999999 end,  
your_column

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X