Sql 按升序排列字符,然后按升序排列数字

Sql 按升序排列字符,然后按升序排列数字,sql,sql-server,tsql,sorting,sql-order-by,Sql,Sql Server,Tsql,Sorting,Sql Order By,选择时,是否有一个简单的技巧可以将排序顺序更改为先字符值升序,然后数字值升序 SELECT mycol FROM mytable ORDER BY mycol 结果: 1C 8Q 9G AR BZ IT IT BZ AR 9G 8Q 1C 使用DESC: SELECT mycol FROM mytable ORDER BY mycol DESC 结果: 1C 8Q 9G AR BZ IT IT BZ AR 9G 8Q 1C 预期结果: AR BZ

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

   SELECT mycol
     FROM mytable
 ORDER BY mycol
结果:

1C
8Q
9G
AR
BZ
IT
IT
BZ
AR
9G
8Q
1C
使用DESC:

   SELECT mycol
     FROM mytable
 ORDER BY mycol DESC
结果:

1C
8Q
9G
AR
BZ
IT
IT
BZ
AR
9G
8Q
1C
预期结果:

AR
BZ
IT
1C
8Q
9G
我们可以在这里尝试使用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);
这里的逻辑使用四个级别的排序,mycl中的两个字符分别对应一对。格表达式将字母置于数字之前。在此之后,我们简单地按数字或字母升序排序

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

我们可以在这里尝试使用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);
这里的逻辑使用四个级别的排序,mycl中的两个字符分别对应一对。格表达式将字母置于数字之前。在此之后,我们简单地按数字或字母升序排序

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

试试这个:

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
试试这个:

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

此选项将该列分成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);

此选项将该列分成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);
简单地说:

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
简单地说:

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

关于@TimBiegeleisen和@SalmanA答案的我的变体:

SELECT mycol
FROM mytable
ORDER BY
    CASE WHEN mycol LIKE '[^0-9]%' THEN 0 ELSE 1 END,
    mycol;
我不知道ORDERBY子句中列上的索引是否会影响性能,但可以肯定的是,我会避免函数调用


编辑:嗯,事实上这和@SalmanA的答案几乎是一样的…

我在@TimBiegeleisen和@SalmanA的答案上的变体:

SELECT mycol
FROM mytable
ORDER BY
    CASE WHEN mycol LIKE '[^0-9]%' THEN 0 ELSE 1 END,
    mycol;
我不知道ORDERBY子句中列上的索引是否会影响性能,但可以肯定的是,我会避免函数调用


编辑:事实上,这与@SalmanA的答案几乎相同…

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

SELECT mycol
     FROM mytable
 ORDER BY mycol COLLATE SQL_EBCDIC278_CP1_CS_AS

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

SELECT mycol
     FROM mytable
 ORDER BY mycol COLLATE SQL_EBCDIC278_CP1_CS_AS

当你到达'ZZ'时会发生什么?实际上,你认为它是'99'?你的列只有2个字符吗?在ZZ之后,所有以数值开头的行都应该列出,比如:1A,1B,。。。诸如此类on@LuisCazares在当前的挑战中,是的。我不确定将来是否需要对更多字符的列使用这种排序顺序。这种逻辑可能非常混乱,因此很难回答。哪一个先到:11还是2A?因为11在数字上大于2…当你到达'ZZ'时会发生什么?实际上,你认为它是'99'?你的列只有2个字符吗?在ZZ之后,所有以数值开头的行都应该列出,比如:1A,1B,。。。诸如此类on@LuisCazares在当前的挑战中,是的。我不确定将来是否需要对更多字符的列使用这种排序顺序。这种逻辑可能非常混乱,因此很难回答。哪一个先到:11还是2A?因为11在数字上大于2…这将只在第一个数字上排序,所以它将把'10A'直接放在'1C'之前。这将只在第一个数字上排序,所以它将把'10A'直接放在'1C'之前