How do I sort a VARCHAR column in SQL server that contains numbers?

后端 未结 11 1986
慢半拍i
慢半拍i 2020-11-27 14:08

I have a VARCHAR column in a SQL Server 2000 database that can contain either letters or numbers. It depends on how the application is configured o

相关标签:
11条回答
  • 2020-11-27 14:22
     SELECT *,
           ROW_NUMBER()OVER(ORDER BY CASE WHEN ISNUMERIC (ID)=1 THEN CONVERT(NUMERIC(20,2),SUBSTRING(Id, PATINDEX('%[0-9]%', Id), LEN(Id)))END DESC)Rn ---- numerical
            FROM
                (
    
            SELECT '1'Id UNION ALL
            SELECT '25.20' Id UNION ALL
    
        SELECT 'A115' Id UNION ALL
        SELECT '2541' Id UNION ALL
        SELECT '571.50' Id UNION ALL
        SELECT '67' Id UNION ALL
        SELECT 'B48' Id UNION ALL
        SELECT '500' Id UNION ALL
        SELECT '147.54' Id UNION ALL
        SELECT 'A-100' Id
        )A
    
        ORDER BY 
        CASE WHEN ISNUMERIC (ID)=0                                /* alphabetical sort */ 
             THEN CASE WHEN PATINDEX('%[0-9]%', Id)=0
                       THEN LEFT(Id,PATINDEX('%[0-9]%',Id))
                       ELSE LEFT(Id,PATINDEX('%[0-9]%',Id)-1)
                  END
        END DESC
    
    0 讨论(0)
  • 2020-11-27 14:26

    This may help you, I have tried this when i got the same issue.

    SELECT * FROM tab ORDER BY IIF(TRY_CAST(val AS INT) IS NULL, 1, 0),TRY_CAST(val AS INT);

    0 讨论(0)
  • 2020-11-27 14:31

    One possible solution is to pad the numeric values with a character in front so that all are of the same string length.

    Here is an example using that approach:

    select MyColumn
    from MyTable
    order by 
        case IsNumeric(MyColumn) 
            when 1 then Replicate('0', 100 - Len(MyColumn)) + MyColumn
            else MyColumn
        end
    

    The 100 should be replaced with the actual length of that column.

    0 讨论(0)
  • 2020-11-27 14:32
    select
      Field1, Field2...
    from
      Table1
    order by
      isnumeric(Field1) desc,
      case when isnumeric(Field1) = 1 then cast(Field1 as int) else null end,
      Field1
    

    This will return values in the order you gave in your question.

    Performance won't be too great with all that casting going on, so another approach is to add another column to the table in which you store an integer copy of the data and then sort by that first and then the column in question. This will obviously require some changes to the logic that inserts or updates data in the table, to populate both columns. Either that, or put a trigger on the table to populate the second column whenever data is inserted or updated.

    0 讨论(0)
  • 2020-11-27 14:35

    you can always convert your varchar-column to bigint as integer might be too short...

    select cast([yourvarchar] as BIGINT)
    

    but you should always care for alpha characters

    where ISNUMERIC([yourvarchar] +'e0') = 1
    

    the +'e0' comes from http://blogs.lessthandot.com/index.php/DataMgmt/DataDesign/isnumeric-isint-isnumber

    this would lead to your statement

    SELECT
      *
    FROM
      Table
    ORDER BY
       ISNUMERIC([yourvarchar] +'e0') DESC
     , LEN([yourvarchar]) ASC
    

    the first sorting column will put numeric on top. the second sorts by length, so 10 will preceed 0001 (which is stupid?!)

    this leads to the second version:

    SELECT
          *
        FROM
          Table
        ORDER BY
           ISNUMERIC([yourvarchar] +'e0') DESC
         , RIGHT('00000000000000000000'+[yourvarchar], 20) ASC
    

    the second column now gets right padded with '0', so natural sorting puts integers with leading zeros (0,01,10,0100...) in correct order (correct!) - but all alphas would be enhanced with '0'-chars (performance)

    so third version:

     SELECT
              *
            FROM
              Table
            ORDER BY
               ISNUMERIC([yourvarchar] +'e0') DESC
             , CASE WHEN ISNUMERIC([yourvarchar] +'e0') = 1
                    THEN RIGHT('00000000000000000000' + [yourvarchar], 20) ASC
                    ELSE LTRIM(RTRIM([yourvarchar]))
               END ASC
    

    now numbers first get padded with '0'-chars (of course, the length 20 could be enhanced) - which sorts numbers right - and alphas only get trimmed

    0 讨论(0)
提交回复
热议问题