May 2, 2005 at 1:58 pm
Hi
Sorting a column ascending with varchar data types that contain numeric values returns unexpected results (incorrect order). For instance if values such as 107 and 14 are contained in the results returned, then if the sortorder was ASC, 107 appears before 14, not after - as expected. What is the best way to implement returning the results in the expeced numberic ascending order?
Thanks in advance.
Grant
May 2, 2005 at 2:04 pm
******************
Dinakar Nethi
Life is short. Enjoy it.
******************
May 3, 2005 at 1:09 am
Please post some sample data.
Are the numbers always at the beginning, somewhere in between or at the end of the string?
--
Frank Kalis
Microsoft SQL Server MVP
Webmaster: http://www.insidesql.org/blogs
My blog: http://www.insidesql.org/blogs/frankkalis/[/url]
May 3, 2005 at 6:51 am
The problem you have is that your data is not sorted the way you assume and is based on the rules of the data type in use.
If all the data is numeric and that is all it ever will be then you should consider changing the field to and numeric data type such as decimal or int then the issue will be moot.
However that said as the data is stored as character data the sort will be based on the character sorting rules.
As such if the data contained
All and Access and Bernard it will sort
Access
All
Bernard
Becuase the charcters are sorted 1 position at a time. The same is true with numbers stored in character type fields
1 and 2 and 114 will sort
1
114
2
because the first character decides sort position first then the next character and so on.
Now if you cannot change your data type but the rule of all are numbers is still true then using the CONVERT method mentioned before should help but you really should use CAST
ORDER BY CAST(<column> as int)
From BOL
Use CAST rather than CONVERT if you want Transact-SQL program code to comply with SQL-92. Use CONVERT rather than CAST to take advantage of the style functionality in CONVERT.
Now if you have data mingled in that is not numeric then you will have a lot of trouble and will not be able to sort as you want unless you apply leading 0's out to the maximum lenght of the data in the table.
So if you have a varchar(8) column to sort the numeric data properly you can do like so
'
ORDER BY
(CASE WHEN IsNumeric(<column> = 1 THEN RIGHT(replicate('0',8) + RTRIM(<column>,8) ELSE <column> END)
With that when 1 and 2 and 114 occurr the data looks for sorting like this.
00000001
00000002
00000114
This will be transparent to anyone looking at it as the data for the column is output as normal unless you apply some special formating or other concatination.
May 3, 2005 at 6:58 am
Actually, this is very much expected sorting behaviour.
Remember that computers never makes any assumptions, they just do what you tell them to. In addition to this, when you deal with strings - ie '107' and '14', you must be aware of how that looks to the comp.
Letters aren't seen as 'a', 'b', '1' or '7' - they are seen as their numerical ASCII values. Thus, when you sort '107' and '14', you're really asking the order of 494855 and 4952. AS we can see, 494855 is larger than 4952, so when sorted ascending, it comes first. '107' is ASCII codes 49, 48 and 55. What this means in reality, is that the datatypes involved makes all the difference. Strings doesn't sort like numbers do, even if we might read '107' as a numeric.
See the pattern?
/Kenneth
May 3, 2005 at 7:11 am
Actually rereading the thread and the "best" advise here is to split numbers from strings into two columns. What you describe is indeed expected behaviour. There are, of course, workarounds possible to get what you expect. that's why I said, post sample data. But every workaround is a kludge at best.
--
Frank Kalis
Microsoft SQL Server MVP
Webmaster: http://www.insidesql.org/blogs
My blog: http://www.insidesql.org/blogs/frankkalis/[/url]
May 3, 2005 at 9:19 am
I was merely trying to point out the fine difference between 'expected' and 'intended'... What we intend may not always be what we can expect
/Kenneth
May 3, 2005 at 9:32 am
... and viceversa
* Noel
May 4, 2005 at 4:06 am
Lets say that your column data type is varchar(50).
In such case it gonna be:
ORDER BY case when ISNUMERIC(ColumnName) = 1 then REPLICATE ('0', 50 - LEN(LTRIM(ColumnName))) + LTRIM(ColumnName) else ColumnName end
It will bring you desired order, but it gonna be really slooooow, because it cannot use any index.
Suggession: use right datatype.
_____________
Code for TallyGenerator
Viewing 9 posts - 1 through 8 (of 8 total)
You must be logged in to reply to this topic. Login to reply