57

VARCHARSQL Server 2000数据库中有一个可以包含字母或数字的列。这取决于如何在前端为客户配置应用程序。

当它确实包含数字时,我希望它按数字排序,例如“1”、“2”、“10”而不是“1”、“10”、“2”。仅包含字母或字母和数字(例如“A1”)的字段可以按字母顺序正常排序。例如,这将是可接受的排序顺序。

1
2
10
A
B
B1

实现这一目标的最佳方法是什么?

4

11 回答 11

82

一种可能的解决方案是用前面的字符填充数值,以使所有数值具有相同的字符串长度。

这是使用该方法的示例:

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

100应该替换为该列的实际长度。

于 2008-09-23T08:29:07.530 回答
13

有几种可能的方法可以做到这一点。

一个是

SELECT
 ...
ORDER BY
  CASE 
    WHEN ISNUMERIC(value) = 1 THEN CONVERT(INT, value) 
    ELSE 9999999 -- or something huge
  END,
  value

ORDER BY 的第一部分将所有内容转换为 int(对于非数字具有巨大的价值,最后排序),然后最后一部分处理字母。

请注意,在大量数据上,此查询的性能可能至少适度可怕。

于 2008-09-23T08:13:26.677 回答
5
select
  Field1, Field2...
from
  Table1
order by
  isnumeric(Field1) desc,
  case when isnumeric(Field1) = 1 then cast(Field1 as int) else null end,
  Field1

这将按照您在问题中给出的顺序返回值。

进行所有这些转换后性能不会太好,因此另一种方法是向存储数据的整数副本的表中添加另一列,然后先按该列排序,然后按相关列排序。这显然需要对在表中插入或更新数据的逻辑进行一些更改,以填充两列。要么,要么在表上放置一个触发器,以便在插入或更新数据时填充第二列。

于 2008-09-23T08:19:11.033 回答
5
SELECT *, CONVERT(int, your_column) AS your_column_int
FROM your_table
ORDER BY your_column_int

或者

SELECT *, CAST(your_column AS int) AS your_column_int
FROM your_table
ORDER BY your_column_int

我认为两者都相当便携。

于 2011-01-13T20:55:28.707 回答
5

您始终可以将 varchar-column 转换为 bigint,因为整数可能太短...

select cast([yourvarchar] as BIGINT)

但你应该始终关心字母字符

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

+'e0' 来自http://blogs.lessthandot.com/index.php/DataMgmt/DataDesign/isnumeric-isint-isnumber

这会导致你的陈述

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

第一个排序列会将数字放在顶部。第二个按长度排序,所以 10 将在 0001 之前(这很愚蠢?!)

这导致了第二个版本:

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

第二列现在用“0”填充,因此自然排序将带有前导零的整数(0,01,10,0100 ...)以正确的顺序(正确!) - 但所有alpha都将用“0”增强-chars(性能)

所以第三个版本:

 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

现在数字首先用'0'字符填充(当然,长度 20 可以增强) - 对数字进行正确排序 - alphas 只会被修剪

于 2013-04-03T07:35:17.060 回答
4

我以一种非常简单的方式解决了这个问题,在“顺序”部分写了这个

ORDER BY (
sr.codice +0
)
ASC

这似乎工作得很好,事实上我有以下排序:

16079   Customer X 
016082  Customer Y
16413   Customer Z

所以0前面的16082被认为是正确的。

于 2011-07-21T09:09:52.170 回答
2

这似乎有效:

select your_column  
from your_table  
order by   
case when isnumeric(your_column) = 1 then your_column else 999999999 end,  
your_column   
于 2008-09-23T08:23:48.120 回答
0

此查询对您有帮助。在此查询中,数据类型为 varchar 的列按良好顺序排列。例如 - 此列中的数据为:- G1、G34、G10、G3。因此,运行此查询后,您会看到结果:- G1,G10,G3,G34。

SELECT *,
       (CASE WHEN ISNUMERIC(column_name) = 1 THEN 0 ELSE 1 END) IsNum
FROM table_name 
ORDER BY IsNum, LEN(column_name), column_name;
于 2017-05-22T10:08:08.203 回答
0

这可能会对你有所帮助,当我遇到同样的问题时,我已经尝试过了。

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

于 2018-05-28T08:19:28.630 回答
-1
SELECT FIELD FROM TABLE
ORDER BY 
  isnumeric(FIELD) desc, 
  CASE ISNUMERIC(test) 
    WHEN 1 THEN CAST(CAST(test AS MONEY) AS INT)
    ELSE NULL 
  END,
  FIELD

根据此链接,您需要先转换为 MONEY,然后再转换为 INT,以避免将“$”作为数字进行排序。

于 2008-09-23T08:18:09.600 回答
-1
 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
于 2016-05-10T16:33:05.767 回答