问题
I have searched for days for a way to sort a string as number in mysql.
My rows look like this:
order_column
1.1.2
1.1.100
1.1.1
Ordering ascending by this column in mysql will produce:
1.1.1
1.1.100
1.1.2
I am interested in getting the following result:
1.1.1
1.1.2
1.1.100
Is there a way to produce this result using SQL?
Other possible values of my column:
28.1999.1.1
1
1.1.154.20
100.1.1.1.1.15
Thanks, i appreciate everybody's time.
EDIT: Fast Relational method of storing tree data (for instance threaded comments on articles) Take a look at the first answer, the one by Ayman Hourieh. I am trying to get that solution working. My website has no more than 10k comments per article, so i found a work-around like this:
000001
000002
000002.000001
000002.000001.000001
000002.000002
000002.000003
000003
Basically, putting zeros before my comment counter so that string comparison doesn't fail. But this will only work for 99999 comments. I can add more zeros, lets say 10 zeros, and that will work for 999999999 comments, but i was hoping for a more elegant solution.
回答1:
If string is not too long you can do
ORDER BY cast(replace(your_column_name,'.','') as unsigned);
回答2:
You won't be able to do this efficiently since this will miss all indexes, but if it's a once-off, this will work. Sadly it looks horrible due to MySQL's inability (that I know of) to replace more than one character at a time.
SELECT value FROM TEST ORDER BY
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(value,
'1', '0'),
'2', '0'),
'3', '0'),
'4', '0'),
'5', '0'),
'6', '0'),
'7', '0'),
'8', '0'),
'9', '0'),value;
It will basically replace all digits with a 0 and order by that first. Since . orders before 0, it will correctly order by digit groups. When that's done, just order by value since any values with the same digit groups should order in the correct order.
To make this more efficient, you could store the replaced value as a column in the database so you could index it.
SQLfiddle demo here.
回答3:
This is not going to be efficient and can be cleaned up, but is one idea for how to do this. It relies on a table called integers with a single column called i with 10 rows with the values 0 to 9.
SELECT somefield , SUM(POW(100, occurrences - anInteger) * somefield_split) OrderField
FROM
(SELECT id,anInteger, somefield, SUBSTRING_INDEX(SUBSTRING_INDEX(somefield, ".", anInteger), ".", -1) AS somefield_split, LENGTH(somefield) - LENGTH(REPLACE(somefield, '.', '')) + 1 AS occurrences
FROM splittertest, (SELECT a.i*10+b.i AS anInteger FROM integers a, integers b) Sub1
HAVING occurrences >= anInteger) Sub2
GROUP BY somefield
ORDER BY somefield, OrderField
Idea is the subselect gets a range of numbers from 0 to 99 and splits up the string off dot separated values based on this. It gets the number of dots in the particular string. It then multiplies each bit of the string by 100 to the power of the total number of sections minus the number of this section, and sums on the basis of this.
So 5.10.15 is split to 5, 10 and 15. There are 3 sections so the first is multiplied by 100 to the power of (3 - 0), second is multiplied by 100 to the power of (2 - 0), etc.
This does give strange results if the number of dots varies (ie, the one with more dots will always be larger), but this could be fixed by using the max number of dots on any line when working out the power, rather than the number of dots on that particular line.
Good luck with it!
回答4:
SELECT INET_ATON('10.0.5.9');
Try this function in yours :)
Perhaps that's not an alternative as it's only for IP address type. And you do have more parts than an IP address have.
回答5:
create a new column that is equal to this column with a string replace of '.' with '' (nothing). store this new field as a number. order by this field instead in your queries.
if you cannot add a new column to the table, you could process this in PHP etc.. to the same effect for display purposes on a website for example.
http://php.net/manual/en/function.str-replace.php
回答6:
make sure your column of those numbers is INT not varchar.
if you use varchar your column will be sorted by those who have 1 first and so on ...
回答7:
you can use the following sql
SELECT REPLACE(column_name,'.','') AS column_name1 FROM table_name ORDER BY column_name1;
回答8:
If you are ordering by the last digit group, then
SELECT CAST(MID(order_column,
CHAR_LENGTH(order_column) -
LOCATE('.',REVERSE(order_column))+2) AS DECIMAL) AS order_column_as_number
FROM thetable
ORDER BY order_column_as_number
seems to work.
Doesn't work at all if there are strings without '.' in them, and you would have to extract more parts to order by if you want to order by other groups as well, but this could be a start if you really want it done in sql only.
回答9:
Here my solution for numbers with max 4 decimals :
SELECT myCol, SUBSTRING_INDEX(myCol, ',', 1) * 10000 + LEFT(CONCAT(SUBSTRING_INDEX(myCol, ',', -1), '0000'), 4) as toOrder
FROM `myTable`
ORDER BY toOrder DESC
You can etit that for 8 decimals like this :
SELECT myCol, SUBSTRING_INDEX(myCol, ',', 1) * 100000000 + LEFT(CONCAT(SUBSTRING_INDEX(myCol, ',', -1), '00000000'), 8) as toOrder
FROM `myTable`
ORDER BY toOrder DESC
etc...
来源:https://stackoverflow.com/questions/13934418/mysql-order-string-as-number