Chaîne de commande SQL sous forme de nombre


137

J'ai des numéros enregistrés dans VARCHARune base de données MySQL. Je ne peux pas les faire en INTraison d'autres circonstances dépendantes.

Il les prend comme des caractères et non comme des nombres lors du tri.

Dans la base de données j'ai

1 2 3 4 5 6 7 8 9 10...

Sur ma page, il affiche une liste ordonnée comme celle-ci:

1 10 2 3 4 5 6 7 8 9

Comment puis-je le faire apparaître par ordre croissant de nombres?


5
Vous devriez sûrement avoir stocké les données sous forme de nombre, au lieu d'une chaîne.
Oded

@Oded Vous pouvez avoir des données arbitraires (par exemple des paramètres), que vous souhaitez classer par leur valeur numérique uniquement dans des cas très particuliers.
Glutexo

article très intéressant - est pour MSSQL mais devrait être relativement similaire pour MySQL: essentialsql.com/use-sql-server-to-sort-alphanumeric-values
AquaAlex

Réponses:


256

Si possible, vous devez changer le type de données de la colonne en un nombre si vous ne stockez de toute façon que des nombres.

Si vous ne pouvez pas faire cela, convertissez la valeur de votre colonne en integer explicitement avec

select col from yourtable
order by cast(col as unsigned)

ou implicitement par exemple avec une opération mathématique qui force une conversion en nombre

select col from yourtable
order by col + 0

BTW MySQL convertit les chaînes de gauche à droite. Exemples:

string value  |  integer value after conversion
--------------+--------------------------------
'1'           |  1
'ABC'         |  0   /* the string does not contain a number, so the result is 0 */
'123miles'    |  123 
'$123'        |  0   /* the left side of the string does not start with a number */

3
commander par col * 1 fonctionne parfaitement. Quelle est la magie derrière tout ça? Désolé, je ne suis pas professionnel, donc cette question pourrait être ridicule, mais comment * 1 le change-t-il en numéro?
Jamol

12
MySQL convertit automatiquement la chaîne en un nombre pour effectuer la multiplication avec1
juergen d

1
La première option est la plus appropriée, la seconde a une étape supplémentaire, mais cela fonctionne non moins.
Manatax

5
et si vous avez mélangé une chaîne et un nombre et que vous voulez les deux triés, utilisez "order by col * 1, col"
Hayden Thring

1
@superphonic: Le résultat sera decimal.
juergen d

70

Une autre façon, sans utiliser une seule distribution.

(Pour les personnes qui utilisent JPA 2.0, où aucune diffusion n'est autorisée)

select col from yourtable
order by length(col),col

EDIT: ne fonctionne que pour les entiers positifs


9
c'est un bon, qui a fonctionné avec une colonne qui contient également à la fois un int et une chaîne
Sruit A.Suk

1
Cela ne fonctionnera pas dans tous les cas. Sur le dessus de la tête, les cas qui ne fonctionneront pas sont des mélanges de nombres entiers avec; des nombres négatifs, des nombres avec des zéros non significatifs, des nombres avec des fractions et des mots et des nombres combinés.
WonderWorker le

3
excellente solution sans aucun type de casting et de jonglage, +1
Maksim Luzik

ne semblait pas fonctionner au premier abord, mais cela a fonctionné! Je vous remercie!
try2fly.b4ucry


17

La colonne avec laquelle je trie contient n'importe quelle combinaison d'alpha et de numérique, j'ai donc utilisé les suggestions de cet article comme point de départ et j'ai proposé ceci.

DECLARE @tmp TABLE (ID VARCHAR(50));
INSERT INTO @tmp VALUES ('XYZ300');
INSERT INTO @tmp VALUES ('XYZ1002');
INSERT INTO @tmp VALUES ('106');
INSERT INTO @tmp VALUES ('206');
INSERT INTO @tmp VALUES ('1002');
INSERT INTO @tmp VALUES ('J206');
INSERT INTO @tmp VALUES ('J1002');

SELECT ID, (CASE WHEN ISNUMERIC(ID) = 1 THEN 0 ELSE 1 END) IsNum
FROM @tmp
ORDER BY IsNum, LEN(ID), ID;

Résultats

ID
------------------------
106
206
1002
J206
J1002
XYZ300
XYZ1002

J'espère que cela t'aides


Vous pouvez simplement utiliser 1 - ISNUMERIC(ID)au lieu de (CASE WHEN ISNUMERIC(ID) = 1 THEN 0 ELSE 1 END)pour changer 0 en 1 et vice versa.
S.Serpooshan

7

Cela fonctionne pour moi.

select * from tablename
order by cast(columnname as int) asc

pouvez-vous expliquer pourquoi?
Slavik

la réponse la plus simple, qui fait exactement ce qui est nécessaire, transtyper la chaîne en un int, puis ordonner par cet int dans l'ordre croissant, pas de trucs funky :)
denford mutseriwa

4

Une autre façon de convertir.

Si vous avez un champ de chaîne, vous pouvez le transformer ou sa partie numérique de la manière suivante: ajoutez des zéros non significatifs pour que toutes les chaînes d'entiers aient la même longueur.

ORDER BY CONCAT( REPEAT(  "0", 18 - LENGTH( stringfield ) ) , stringfield ) 

ou commandez par partie d'un champ quelque chose comme 'tensymbols13', 'tensymbols1222' etc.

ORDER BY CONCAT( REPEAT(  "0", 18 - LENGTH( LEFT( stringfield , 10 ) ) ) , LEFT( stringfield , 10 ) ) 

2

Je cherchais aussi un tri des champs qui a un préfixe de lettre. Voici ce que j'ai trouvé la solution. Cela pourrait aider ceux qui recherchent la même solution.

Valeurs de champ:

FL01,FL02,FL03,FL04,FL05,...FL100,...FL123456789

select SUBSTRING(field,3,9) as field from table order by SUBSTRING(field,3,10)*1 desc

SUBSTRING(field,3,9) Je mets 9 parce que 9 me suffit amplement pour contenir des valeurs entières de 9 chiffres maximum.

Le résultat sera donc 123456789 123456788 123456787 ... 100 99 ... 2 1


2

Cela gérera les nombres négatifs, les fractions, la chaîne, tout:

ORDER BY ISNUMERIC(col) DESC, Try_Parse(col AS decimal(10,2)), col;

2

Cela pourrait aider qui cherche la même solution.

select * from tablename ORDER BY ABS(column_name)

0

Si vous utilisez AdonisJS et que vous avez des ID mixtes tels que ABC-202, ABC-201 ..., vous pouvez combiner des requêtes brutes avec Query Builder et implémenter la solution ci-dessus ( https://stackoverflow.com/a/25061144/4040835 ) comme suit:

const sortField =
  'membership_id'
const sortDirection =
  'asc'
const subquery = UserProfile.query()
  .select(
    'user_profiles.id',
    'user_profiles.user_id',
    'user_profiles.membership_id',
    'user_profiles.first_name',
    'user_profiles.middle_name',
    'user_profiles.last_name',
    'user_profiles.mobile_number',
    'countries.citizenship',
    'states.name as state_of_origin',
    'user_profiles.gender',
    'user_profiles.created_at',
    'user_profiles.updated_at'
  )
  .leftJoin(
    'users',
    'user_profiles.user_id',
    'users.id'
  )
  .leftJoin(
    'countries',
    'user_profiles.nationality',
    'countries.id'
  )
  .leftJoin(
    'states',
    'user_profiles.state_of_origin',
    'states.id'
  )
  .orderByRaw(
    `SUBSTRING(:sortField:,3,15)*1 ${sortDirection}`,
    {
      sortField: sortField,
    }
  )
  .paginate(
    page,
    per_page
  )

NOTES: Dans cette ligne: SUBSTRING(:sortField:,3,15)*1 ${sortDirection},

  1. «3» représente le numéro d'index du dernier caractère non numérique avant les chiffres. Si votre ID mixte est «ABC-123», votre numéro d'index sera 4.
  2. «15» est utilisé pour capturer autant de chiffres que possible après le trait d'union.
  3. «1» exécute une opération mathématique sur la sous-chaîne qui convertit efficacement la sous-chaîne en un nombre.

Réf 1: Vous pouvez en savoir plus sur les liaisons de paramètres dans les requêtes brutes ici: https://knexjs.org/#Raw-Bindings Réf 2: Adonis Raw Queries: https://adonisjs.com/docs/4.1/query-builder# _raw_queries


-3

Modifiez votre champ pour qu'il soit INT au lieu de VARCHAR.

Je ne peux pas les rendre INT en raison d'autres circonstances dépendantes.

Ensuite, corrigez d'abord les circonstances dépendantes. Sinon, vous travaillez autour du vrai problème sous-jacent. Utiliser un CAST MySQL est une option, mais cela masque votre mauvais schéma qui devrait être corrigé.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.