web-dev-qa-db-fra.com

Trier la colonne de chaîne contenant des nombres en SQL?

J'essaie de trier la colonne de chaîne ( contenant des nombres ).

// SELECT `name` FROM `mytable` ORDER BY `name` ASC
+----------+
+-- name --+
+----------+
+-- a 1 ---+
+-- a 12 --+
+-- a 2 ---+
+-- a 3 ---+

Vous voyez l'algorithme de tri naturel de Mysql place a 12 après a 1 ( ce qui est correct pour la plupart des applications ), mais j'ai des besoins uniques, donc je veux que le résultat soit trié comme ceci.

+----------+
+-- name --+
+----------+
+-- a 1 ---+
+-- a 2 ---+
+-- a 3 ---+
+-- a 12 --+

Est-il possible avec niquement SQL, ou je dois manipuler l'ensemble de résultats au niveau de l'application?

25
Ish

En partant de l'hypothèse c'est toujours Word_space_NUMBER, cela devrait fonctionner:

SELECT   *
FROM     table
ORDER BY CAST(SUBSTRING(column,LOCATE(' ',column)+1) AS SIGNED)

Utilisez POSITION pour trouver l'espace, SOUS-CHAÎNE pour saisir le numéro après, et CAST pour en faire une valeur comparable.

S'il y a un modèle différent dans la colonne, faites-le moi savoir et j'essaierai de trouver une meilleure solution de contournement.


[~ # ~] modifier [~ # ~] Prouvé pour fonctionner:

mysql> INSERT INTO t (st) VALUES ('a 1'),('a 12'),('a 6'),('a 11');
Query OK, 4 rows affected (0.00 sec)
Records: 4  Duplicates: 0  Warnings: 0

mysql> SELECT * FROM t ORDER BY st;
+----+------+
| id | st   |
+----+------+
|  1 | a 1  |
|  4 | a 11 |
|  2 | a 12 |
|  3 | a 6  |
+----+------+
4 rows in set (0.00 sec)

mysql> SELECT * FROM t ORDER BY CAST(SUBSTRING(st,LOCATE(' ',st)+1) AS SIGNED);
+----+------+
| id | st   |
+----+------+
|  1 | a 1  |
|  3 | a 6  |
|  4 | a 11 |
|  2 | a 12 |
+----+------+

mysql> INSERT INTO t (st) VALUES ('b 1'),('b 12'),('b 6'),('b 11');
Query OK, 4 rows affected (0.00 sec)
Records: 4  Duplicates: 0  Warnings: 0

mysql> SELECT * FROM t ORDER BY CAST(SUBSTRING(st,LOCATE(' ',st)+1) AS SIGNED);
+----+------+
| id | st   |
+----+------+
|  1 | a 1  |
|  5 | b 1  |
|  3 | a 6  |
|  7 | b 6  |
|  4 | a 11 |
|  8 | b 11 |
|  2 | a 12 |
|  6 | b 12 |
+----+------+
8 rows in set (0.00 sec)

mysql> SELECT * FROM t ORDER BY LEFT(st,LOCATE(' ',st)), CAST(SUBSTRING(st,LOCATE(' ',st)+1) AS SIGNED);
+----+------+
| id | st   |
+----+------+
|  1 | a 1  |
|  3 | a 6  |
|  4 | a 11 |
|  2 | a 12 |
|  5 | b 1  |
|  7 | b 6  |
|  8 | b 11 |
|  6 | b 12 |
+----+------+
8 rows in set (0.00 sec)

ignorer mes noms de table/colonne boiteux, mais me donne le résultat correct. Est également allé un peu plus loin et a ajouté un double tri pour casser le préfixe des lettres avec le numérique.

Modifier SUBSTRING_INDEX le rendra un peu plus lisible.

ORDER BY SUBSTRING_INDEX(st, " ", 1) ASC, CAST(SUBSTRING_INDEX(st, " ", -1) AS SIGNED)
36
Brad Christie

Vous pouvez essayer ceci:

ORDER BY CASE
  WHEN ISNUMERIC(column) THEN cast(column as int) 
  else ascii(column[1,1]) 
end
2
tzviki

Jetez un œil aux fonctions MySQL CAST/Convert .

SELECT name FROM mytable ORDER BY CAST(name AS INTEGER) ASC;

Edit: J'ai lu:

J'essaye de trier la colonne de chaîne (contenant des nombres).

... mais je viens de jeter un œil à l'ensemble de résultats. Le a fait-il également partie du contenu? Si c'est le cas, vous pouvez utiliser des fonctions telles que MID pour extraire uniquement la valeur numérique et la transtyper.

Mais si tous les lignes contiennent juste a sans variation, vous pourriez aussi bien l'omettre ...

1
Jim Brissom

Une autre option pourrait être de remplir la chaîne avec des espaces à gauche du nombre (c'est-à-dire d'ajouter des espaces entre le mot et le nombre) et d'utiliser la chaîne résultante pour le tri, comme ceci:

ORDER BY INSERT(
  column,
  LOCATE(' ', column),
  0,
  SPACES(20 - LENGTH(column) + LOCATE(' ', column))
)

La chaîne est supposée être du modèle "Word suivi d'espaces suivis d'un nombre", et le nombre est supposé non négatif (ou il serait mal trié). Le codé en dur 20 est choisi arbitrairement et est censé être la longueur maximale possible de la partie numérique de la chaîne.

0
Andriy M

Ici, j'ai trouvé une autre solution avec la requête suivante en utilisant Convert

select * from tablename where columnname like '%a%' order by Convert(smallint,Replace(columnname,'a',''))
0
Hussain