Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sorting string column containing numbers in SQL?

I am trying to sort string column (containing numbers).

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

You see natural sorting algorithm of Mysql is placing a 12 after a 1 (which is ok for most apps), But I have unique needs, so I want result should be sorted like this.

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

Is it possible with just SQL, or I have to manipulate result-set at application level?

like image 639
Ish Avatar asked Feb 08 '11 23:02

Ish


People also ask

How do I sort a column by number in SQL?

The ORDER BY statement in SQL is used to sort the fetched data in either ascending or descending according to one or more columns. By default ORDER BY sorts the data in ascending order. We can use the keyword DESC to sort the data in descending order and the keyword ASC to sort in ascending order.

How do you break ties in SQL ORDER BY?

Breaking a "tie" in a sort is as easy as specifying a second column to ORDER BY : use a comma to specify the second (or third or nth) column to use in sorting.

How do I sort multiple columns in ascending order in SQL?

Syntax: SELECT * FROM table_name ORDER BY column_name; For Multiple column order, add the name of the column by which you'd like to sort records first. The column that is entered at first place will get sorted first and likewise.


2 Answers

Going on the assumption it's always WORD_space_NUMBER this should work:

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

Use POSITION to find the space, SUBSTRING to grab the number after it, and CAST to make it a comparable value.

If there is a different pattern to the column, let me know and I'll try to devise a better work-around.


EDIT Proven to work:

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) 

ignore my lame table/column names, but gives me the correct result. Also went a little further and added double sort to break letters prefix with numeric.

Edit SUBSTRING_INDEX will make it little more readable.

ORDER BY SUBSTRING_INDEX(st, " ", 1) ASC, CAST(SUBSTRING_INDEX(st, " ", -1) AS SIGNED) 
like image 155
Brad Christie Avatar answered Sep 28 '22 02:09

Brad Christie


You can try this:

ORDER BY CASE   WHEN ISNUMERIC(column) THEN cast(column as int)    else ascii(column[1,1])  end 
like image 25
tzviki Avatar answered Sep 28 '22 00:09

tzviki