Looking through the records in the Teacher! database, I realized that some people are using numbers instead of names to represent their students. That’s fine by me; one of my design objectives with Teacher! is to get the application out of the way. That means it doesn’t care how you choose to refer to your students, and it doesn’t force you to do it in any particular way.

So if you want to just use first names, just use last names, just use number or use some other wacky combination, it doesn’t matter. The application doesn’t choke just because you decided to call one of your students R2D2 (hey, whatever floats your boat).

But the numeric student names weren’t sorting correctly in the class lists. Because Teacher! was expecting a text string, not a number, it was sorting by alpha order, not numerically. That’s no good.

So I did a little digging and came up with an answer. You can force a MySQL SELECT statement to sort naturally (first by letters and then by numbers) by doing this:


SELECT names FROM your_table ORDER BY names + 0 ASC


The added “0” forces it to sort the way you want it to, but doesn’t alter your data in any way. Pretty neat!

For those of you using Ruby On Rails, you can define the sort order in your model. So, for example, in Teacher!, I have a Classroom model that has_and_belongs_to_many => :students. So in the classroom.rb model I have this:


class Classroom < ActiveRecord::Base
has_and_belongs_to_many :students,:order => 'firstname + 0 ASC'
...
end


That way my :classroom objects always have students collections that are sorted alphanumerically. Hurray!


<—3a60a642374c64a449e206fa2e7064e1—>


17 Responses to “How to do natural alpha-numeric sort in MySQL”  

  1. 1 Anonymous

    Worked for me, thanks!

  2. 2 richard

    What about when you are concatanating fields… eg
    select concat(first name, last name) from names order by ???

    what do you put in the question marks??

  3. 3 Bruno

    Well, it depends on how you want to order your result. If you want to order by last name, you’d put “order by last_name”. If you wanted to order by the concatenated field, you’d do “SELECT concat(first_name, last_name) as full_name ORDER by full_name. In either case you can add ” 0” to force MySQL to sort naturally.

  4. 4 Jeremy

    It doesn’t sort completely naturally…any idea on how to get it to sort completely naturally.

    For example, most people could consider A1, A2, A3…A10, A11 to be a natural order, but 0 sorts this as A1, A10, A11, A2, A3

    Any ideas?

  5. 5 V@no

    Also, besides what Jeremy said, this little “fix” will sort alpha-based entries first, and only then numeric.
    For example if you have the following entries in the database:
    1, A1, 11, A11, 2, A2
    The result will be (ASC):
    A1, A11, A2, 1, 2, 11
    But the expected result supposed be:
    1, 2, 11, A1, A2, A11

    So basicaly this fix only works if you have ONLY numeric entries…

  6. 6 Amr Boghdady

    Thanks !
    It worked in sorting Ip addresses :)

  7. 7 Kaleb

    Thank you, this solution worked perfectly.

  8. 8 Paul

    Just what i was looking for. Thanks for the rails example!

  9. 9 Bart

    You saved my day!!
    Thnx, Bart

  10. 10 Erik

    Worked exactly how i wanted it to! thnx

  11. 11 Jonathan Lee

    A great little tip which has saved me a lot of hassle on a CMS that I’m working on!

    Thanks

    Jonathan

  12. 12 Johan Meiring

    To solve the “A1, A11, A2, 1, 2, 11” problem a bit better (although sill not perfect) I use the following:

    order by LPAD ASC
    where 25 is the length of your varchar field.

    The left-pads the string with spaces so that shorter strings are always above longer ones.

    This should product the expected result of 1,2,11,A1,A2,A11
    (mostly)

    Johan

  13. 13 Tommy

    I had the same problem but with ponctuation (i.e Q-345-5678, Qchl-5448-7667…)

    i.e of order with normal ORDER BY clause————————————Q-345-5678
    Q-645-5666
    Qchl-5448-7667
    Qchl-625-777

    I came out with this

    SELECT * FROM tblPierres WHERE CategoryID=’$CategoryID’ ORDER BY SUBSTRING_INDEX(QuartzID,’-’,1), SUBSTRING_INDEX(QuartzID,’-’,-2) 0 ASC

    Lets look at the query—————————————**FIRST==
    SUBSTRING_INDEX(QuartzID,’-’,1)

    **Isolate the alpha from numeric string and look at Alpha

    i.e of order (Same as normal query)——————-
    Q-345-5678
    Q-645-5666
    Qchl-5448-7667
    Qchl-625-777

    **SECOND==
    SUBSTRING_INDEX(QuartzID,’-’,-2)

    **Isolate the alpa from numeric string and order it by Numeric

    So first it orders it by Alpha then takes the result and look at Numeric

    i.e of order (No change from previous)——————-
    Q-345-5678
    Q-645-5666
    Qchl-5448-7667
    Qchl-625-777

    But now with 0 ASC, this is where its happen :
    It Takes all alpha and order it
    and takes all numeric value within the same alpha and order it

    i.e of final order——————-
    Q-345-5678
    Q-645-5666
    Qchl-625-777
    Qchl-5448-7667

  14. 14 Xbalanqué

    Thankx, the solution works perfectly!

  15. 15 OD2

    Really cool!! Thanks.

  1. 1 http://www.nitt.edu/notice/images/f/voyeur-cam/free-cam-girls.html
  2. 2 Zovirax side effects.


Leave a Reply