web-dev-qa-db-fra.com

Comment trier une colonne VARCHAR dans SQL Server qui contient des nombres?

J'ai une colonne VARCHAR dans un SQL Server 2000 base de données pouvant contenir des lettres ou des chiffres. Cela dépend de la configuration de l'application sur le front-end pour le client.

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

1
2
10
A
B
B1

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

49
Tim C

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

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

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

74
Aleris

Il existe plusieurs façons de procéder.

L'une serait

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

la première partie de ORDER BY convertit tout en entier (avec une valeur énorme pour les non-numériques, pour trier en dernier) puis la dernière partie s'occupe de l'alphabet.

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

12
Cowan
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.

5
JohnB
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 donné dans votre question.

Les performances ne seront pas trop bonnes avec tout ce casting, donc une autre approche consiste à ajouter une autre colonne à la table dans laquelle vous stockez une copie entière des données, puis triez en fonction de celle-ci en premier, puis de 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, pour remplir les deux colonnes. Soit cela, soit placez 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.

5
Luke Bennett

vous pouvez toujours convertir votre colonne varchar en bigint car l'entier peut être trop court ...

select cast([yourvarchar] as BIGINT)

mais vous devez toujours vous soucier des caractères alpha

where ISNUMERIC([yourvarchar] +'e0') = 1

le + 'e0' vient de http://blogs.lessthandot.com/index.php/DataMgmt/DataDesign/isnumeric-isint-isnumber

cela conduirait à votre déclaration

SELECT
  *
FROM
  Table
ORDER BY
   ISNUMERIC([yourvarchar] +'e0') DESC
 , LEN([yourvarchar]) ASC

la première colonne de tri mettra le numérique en haut. le second trie par longueur, donc 10 précédera 0001 (ce qui est stupide?!)

cela conduit à la deuxième version:

SELECT
      *
    FROM
      Table
    ORDER BY
       ISNUMERIC([yourvarchar] +'e0') DESC
     , RIGHT('00000000000000000000'+[yourvarchar], 20) ASC

la deuxième colonne est maintenant complétée à droite par '0', donc le tri naturel met les entiers avec des zéros en tête (0,01,10,0100 ...) dans le bon ordre (correct!) - mais tous les alphas seraient améliorés avec '0' -chars (performance)

donc troisième version:

 SELECT
          *
        FROM
          Table
        ORDER BY
           ISNUMERIC([yourvarchar] +'e0') DESC
         , CASE WHEN ISNUMERIC([yourvarchar] +'e0') = 1
                THEN RIGHT('00000000000000000000' + [yourvarchar], 20) ASC
                ELSE LTRIM(RTRIM([yourvarchar]))
           END ASC

maintenant, les chiffres sont d'abord remplis de caractères `` 0 '' (bien sûr, la longueur 20 pourrait être améliorée) - ce qui trie les chiffres correctement - et les alphas ne sont coupés

4
Bernhard

Je l'ai résolu de manière très simple en écrivant ceci dans la partie "commande"

ORDER BY (
sr.codice +0
)
ASC

Cela semble très bien fonctionner, en fait j'ai eu le tri suivant:

16079   Customer X 
016082  Customer Y
16413   Customer Z

Alors le 0 en face de 16082 est considéré correctement.

4
Orz

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   
2
Corey Trager

Cette requête vous est utile. Dans cette requête, une colonne a le type de données varchar est organisée par bon ordre. Par exemple - Dans cette colonne, les données sont: - G1, G34, G10, G3. Ainsi, après avoir exécuté cette requête, vous voyez les résultats: - G1, G10, G3, G34.

SELECT *,
       (CASE WHEN ISNUMERIC(column_name) = 1 THEN 0 ELSE 1 END) IsNum
FROM table_name 
ORDER BY IsNum, LEN(column_name), column_name;
0
Nitika Chopra

Cela peut vous aider, j'ai essayé cela lorsque j'ai eu le même problème.

SELECT * FROM tab ORDER BY IIF(TRY_CAST(val AS INT) IS NULL, 1, 0),TRY_CAST(val AS INT);

0
Dennis
SELECT FIELD FROM TABLE
ORDER BY 
  isnumeric(FIELD) desc, 
  CASE ISNUMERIC(test) 
    WHEN 1 THEN CAST(CAST(test AS MONEY) AS INT)
    ELSE NULL 
  END,
  FIELD

Selon ce lien vous devez effectuer un cast vers MONEY puis INT pour éviter de commander '$' en nombre.

0
Matt Mitchell