0

Can someone please explain this strange behaviour:

select a from (
    select '1' as a
    union all
    select '2' as a
    union all
    select '-3' as a
) as b
order by a desc

select a from (
    select '4' as a
    union all
    select '5' as a
    union all
    select '-3' as a
) as b
order by a desc

Result for query 1:

-3
2
1

Result for query 2:

5
4
-3

It looks like - character is ignored. I though, that SQL Server orders varchars based on ASCII code.

So expected result would be:

2
1
-3   //ascii - is before 0-9

and:

 5
 4
-3  //ascii - is before 0-9

I get same result if I add a letter before number:

select a from (
    select 'a1' as a
    union all
    select 'a2' as a
    union all
    select '-a3' as a
) as b
order by a desc

select a from (
    select 'a4' as a
    union all
    select 'a5' as a
    union all
    select '-a3' as a
) as b
order by a desc
5
  • 3
    I suspect the collation setting will be important. It's almost always better to control Sort Order with an explicit numeric SortOrder column that you define. Commented Feb 5, 2019 at 9:20
  • Possible duplicate of SQL Sorting and hyphens? Commented Feb 5, 2019 at 9:22
  • Those strings are strings, not numeric values. Commented Feb 5, 2019 at 9:26
  • 1
    String value '1000' will be sorted before '9', while numerical value 9 will be sorted before 1000. Commented Feb 5, 2019 at 9:32
  • @Makla: I have checked your query and it gives me perfect result Commented Feb 5, 2019 at 9:38

3 Answers 3

4

Actual sort order in SQL Server depends totally on the active collation (either the default one, or a collation that is specified explicitly).

If e.g. you use a binary collation, you'll get what you were expecting for this case:

select a from (
    select '1' as a
    union all
    select '2' as a
    union all
    select '-3' as a
) as b
order by a COLLATE Latin1_General_BIN desc
/* Result: 2, 1, -3  */

select a from (
    select '4' as a
    union all
    select '5' as a
    union all
    select '-3' as a
) as b
order by a COLLATE Latin1_General_BIN desc
/* Result: 5, 4, -3  */

To see all collations, run this:

select * from sys.fn_helpcollations()
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks @PeterB, it would be awesome to explain (share a link) why binary collation acts like it does. (I will try to add this information myself if I found it.)
Here is an article with some more info on binary collations: mikerodionov.com/2018/06/sql-servers-binary2-collations
1

You should set the collation to Latin1_General_BIN like this :

select a from (
select '1' as a
union all
select '0' as a
union all
select '-1' as a
) as b
order by a COLLATE Latin1_General_BIN desc

1 Comment

How is this different from Peter B answer?
1

If you use numbers instead of strings ...

select a from (
    select 1 as a
    union all
    select 2 as a
    union all
    select -3 as a
) as b
order by a desc

... then the numbers are sorted as expected:

2
1
-3

1 Comment

Of course but I don't have number. I also don't have values 2, 3 and -1. This was simplified example.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.