2011-02-08 18 views
24

Estoy tratando de ordenar la columna de cadena (que contiene los números).Ordenando columna de cadena que contiene números en SQL?

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

Ves algoritmo de ordenación natural de MySQL está colocando después a 12a 1 (que está bien para la mayoría de aplicaciones), pero tengo necesidades únicas, así que quiero resultado debe ser clasificada como este.

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

¿Es posible con solo SQL, o tengo que manipular conjunto de resultados, a nivel de aplicación?

+0

es el prefijo alfabético siempre una longitud constante para todas las filas? –

+0

No, es una cadena normal que se repite a veces. – Ish

+2

Así que algo así como 'ordenar por izquierda (nombre, 1), emitir (SUBCADENA (nombre, 2) como int)' no funcionaría entonces. ¿Puede proporcionar datos más variados que ilustren sus necesidades exactas? –

Respuesta

36

ir en el supuesto de siempre WORD_space_NUMBER esto debería funcionar:

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

Uso POSITION para encontrar el espacio, SUBSTRING para tomar el número después de él, y CAST para que sea un valor comparable.

Si hay un patrón diferente en la columna, házmelo saber y trataré de idear una mejor solución.


EDITAR demostrada para trabajar:

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) 

ignorar mis nombres de tabla/columna cojos, pero me da el resultado correcto. También fue un poco más allá y agregó una clasificación doble para separar el prefijo de letras con numérico.

Edición SUBSTRING_INDEX hará que sea poco más legible.

ORDER BY SUBSTRING_INDEX(st, " ", 1) ASC, CAST(SUBSTRING_INDEX(st, " ", -1) AS SIGNED) 
+0

Lo tienes hombre ... gracias un millón – Ish

+0

@ish: No hay problema. También puede agregar un 'IZQUIERDO (columna, LOCALIZAR ('', columna))' en el orden por agruparlo primero por las letras, luego por los números. –

+0

gracias por más opciones :), Su solución original cumplió mi propósito. Y aprendí sobre las capacidades 'CAST' de MySQL ... aplausos – Ish

1

Eche un vistazo a las funciones de MySQL CAST/Convert.

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

Editar: leí:

que estoy tratando de resolver columna de cadena (números que contienen).

... pero solo eché un vistazo al conjunto de resultados. ¿Es el a en realidad también parte de los contenidos? Si es así, puede usar funciones como MID para extraer solo el valor numérico y lanzarlo.

Pero si todos filas contienen solo a sin variación, que también podría omitirlo ...

+0

error de mysql 'sintaxis correcta para usar cerca de 'INTEGER) ASC LIMIT 0, 30' – Ish

+0

@Ish: Debido a lo mismo que olvidé. Debe usar SIGNED/UNSIGNED cuando usa CAST/CONVERT. –

0

Otra opción podría ser rellenar la cadena con espacios a la izquierda del número (es decir,añadir espacios entre la palabra y el número) y el uso de la cadena resultante de clasificar, comething como esto:

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

La cadena se supone que es de la 'palabra seguida por espacio (s) seguido de un número' patrón, y se supone que el número no es negativo (o se ordenaría incorrectamente). El codificado 20 se elige arbitrariamente y se supone que es la longitud máxima posible de la parte numérica de la cadena.

0

Aquí encontré con otra solución siguiente consulta utilizando Convertir

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

Puede probar esto:

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