2

I'm dealing with alpha numeric column values that need to be sorted by letters and then by numbers.

Example of data:

  • a1
  • a10
  • a11
  • ab2
  • ab21
  • ab22
  • a1a
  • a1b

Needs to be sorted as follows:

  • a1
  • a1a
  • a1b
  • a2
  • a3
  • ab1
  • ab2
  • ab3
  • ...

Need advice on how to sort this in SQL.

Thanks.

7
  • 1
    is the string format consistent? also what is the dbms being used? Commented Oct 18, 2016 at 0:19
  • Not exactly, numeric portion is preceded by 1-3 letters. Commented Oct 18, 2016 at 0:20
  • Please tag your question with the database you are using. Commented Oct 18, 2016 at 1:00
  • is this a VARCHAR field? Is it not working with a regular ORDER BY clause? IF not, what's the collation? Commented Oct 18, 2016 at 1:34
  • It is a VARCHAR field, however you end up getting 1, 10, 11, 2, 20, 21 instead of 1,2,3 etc. Commented Oct 18, 2016 at 3:02

2 Answers 2

1

The below may work for alphanumerics. However be warned that the behaviour is undefined for non alphanumeric values.

WITH A (A, N) AS (
    SELECT A, 3 + LEN(A) FROM (
        SELECT 'a1'
        UNION ALL
        SELECT 'a10'
        UNION ALL
        SELECT 'a11'
        UNION ALL
        SELECT 'ab2'
        UNION ALL
        SELECT 'ab21'
        UNION ALL
        SELECT 'ab22'
        UNION ALL
        SELECT 'a1a'
        UNION ALL
        SELECT 'a1b'
        UNION ALL
        SELECT 'a1'
        UNION ALL
        SELECT 'a1a'
        UNION ALL
        SELECT 'a1b'
        UNION ALL
        SELECT 'a2'
        UNION ALL
        SELECT 'a3'
        UNION ALL
        SELECT 'a9'
        UNION ALL
        SELECT 'ab1'
        UNION ALL
        SELECT 'ab2'
        UNION ALL
        SELECT 'ab3'
    ) T (A)
), B (A, N, I, C, D, X) AS (
    SELECT A, N, 3, CAST(SUBSTRING(A, 1, 1) AS VARCHAR(255)), CAST(SUBSTRING(A, 2, 1) AS VARCHAR(255)), CAST('' AS VARCHAR(255)) FROM A
    UNION ALL
    SELECT A, N, I + 1, D, CAST(SUBSTRING(A, I, 1) AS VARCHAR(255)), CASE WHEN ASCII(C) BETWEEN 48 AND 57 AND ASCII(D) BETWEEN 48 AND 57 THEN CAST(X + CHAR(10 + ASCII(D)) AS VARCHAR(255)) WHEN 58 > ASCII(C) THEN CAST(X + C AS VARCHAR(255)) ELSE CAST(X + CHAR(3 + ASCII(C)) AS VARCHAR(255)) END FROM B WHERE I <= N
)
SELECT A FROM B WHERE I = N
ORDER BY X COLLATE Latin1_General_BIN

The code currently sorts in a Case Sensitive manner, but may be tweaked to do a case insensitive sort as well, for example by using

ORDER BY UPPER(X) COLLATE Latin1_General_BIN

or

ORDER BY LOWER(X) COLLATE Latin1_General_BIN
Sign up to request clarification or add additional context in comments.

Comments

0

You tried?

SELECT column_x
FROM table_name x
ORDER BY x.column_name ASC|DESC, x.column_name ASC|DESC;

Comments

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.