【问题标题】:Sort characters ascending then numbers ascending将字符升序排序,然后数字升序
【发布时间】:2019-09-02 05:07:43
【问题描述】:

选择时是否有一个简单的技巧可以将排序顺序更改为“第一个字符值升序,然后数值升序”?

   SELECT mycol
     FROM mytable
 ORDER BY mycol

结果:

1C
8Q
9G
AR
BZ
IT

使用 DESC:

   SELECT mycol
     FROM mytable
 ORDER BY mycol DESC

结果:

IT
BZ
AR
9G
8Q
1C

想要的结果:

AR
BZ
IT
1C
8Q
9G

【问题讨论】:

  • 当你到达'ZZ'(实际上是'99')会发生什么?
  • 您的列是否只有 2 个字符?
  • ZZ 之后所有以数值开头的行都应该列出来,比如:1A, 1B,...等等
  • @LuisCazares 在当前的挑战中是的。我不确定将来是否需要这种排序顺序来处理更多字符的列。
  • 这种逻辑会比较混乱,所以很难回答。哪个先出现:112A? (因为 11 在数值上大于 2...)

标签: sql sql-server tsql sorting sql-order-by


【解决方案1】:

我们可以在这里尝试使用ASCII 函数和CASE 表达式:

SELECT mycol
FROM mytable
ORDER BY
    CASE WHEN LEFT(mycol, 1) LIKE '[A-Z]' THEN 0 ELSE 1 END,
    LEFT(mycol, 1),
    CASE WHEN RIGHT(mycol, 1) LIKE '[A-Z]' THEN 0 ELSE 1 END,
    RIGHT(mycol, 1);

Demo

这里的逻辑使用了四个级别的排序,mycol 中的两个字符中的每一个都有一对。 CASE 表达式将字母放在数字之前。在此之后,我们只需按数字或字母升序排序。

另一种方法是将您的列视为以 36 为基数的数字(10 位数字加 26 个字母),然后仅根据转换回以 10 为基数的十进制数进行排序。但是,这可能比我上面发布的解决方案更丑陋,更令人费解。

【讨论】:

    【解决方案2】:

    试试这个:

    DECLARE @mytable TABLE
    ( MyCol VARCHAR(3))
    
    insert @mytable VALUES ('IT'),('BZ'),('AR'),('1C'),('8Q')
    
    SELECT
         MyCol
    FROM @mytable
    ORDER BY PATINDEX('[0-9]%',MyCol),MyCol
    

    【讨论】:

    • 这只会对第一个数字进行排序,因此会将 '10A' 直接放在 '1C' 之前
    【解决方案3】:

    此选项会将列分为 2 以分隔数字和字母。

    SELECT *
    FROM (VALUES('1C'),('8Q'),('9G'),('AR'),('BZ'),('IT'))x(MyCol)
    ORDER BY SUBSTRING(MyCol, 0, PATINDEX( '%[A-Z]%', MyCol)),
             SUBSTRING(MyCol, PATINDEX( '%[A-Z]%', MyCol), 10);
    

    【讨论】:

      【解决方案4】:

      简单地说:

      SELECT *
      FROM (VALUES 
          ('1C'),
          ('8Q'),
          ('9G'),
          ('AR'),
          ('BZ'),
          ('IT'),
          ('11'),
          ('2A')
      ) AS tbl(col)
      ORDER BY CASE WHEN col LIKE '[0-9]%' THEN 2 ELSE 1 END
             , col
      

      输出:

      AR
      BZ
      IT
      11
      1C
      2A
      8Q
      9G
      

      【讨论】:

        【解决方案5】:

        我对@TimBiegeleisen 和@SalmanA 的回答的变体:

        SELECT mycol
        FROM mytable
        ORDER BY
            CASE WHEN mycol LIKE '[^0-9]%' THEN 0 ELSE 1 END,
            mycol;
        

        (我不知道 ORDER BY 子句中列的索引是否会影响性能,但可以肯定的是我会避免函数调用。)

        编辑:嗯,实际上它与@SalmanA 的答案几乎相同......

        【讨论】:

          【解决方案6】:

          我想出的另一个解决方案是使用COLLATE 作为ORDER BY 子句,使用EBCDIC 排序规则。性能方面与其他解决方案一样快。也许更容易写,但在没有 cmets 的情况下读起来有点棘手。一个优点是,它也适用于超过 1 或 2 个字符的列。

          SELECT mycol
               FROM mytable
           ORDER BY mycol COLLATE SQL_EBCDIC278_CP1_CS_AS
          

          【讨论】:

            猜你喜欢
            • 2011-10-03
            • 1970-01-01
            • 2017-11-06
            • 1970-01-01
            • 2011-01-23
            • 1970-01-01
            • 2018-01-14
            • 1970-01-01
            • 2020-12-10
            相关资源
            最近更新 更多