排序以数字结尾的字符串,少数以非数字字符结尾的字符串除外

order strings which end with number with a few exceptions that end with non-numerical character

我正在使用这个脚本:

IF OBJECT_ID('tempdb..#Temp') IS NOT NULL DROP TABLE #Temp

CREATE TABLE #Temp
(
    SomeString NVARCHAR(10)
)

INSERT INTO #Temp
SELECT 'X1'
    UNION 
SELECT 'X10'
    UNION 
SELECT 'X2'

-- undesired result
SELECT * FROM #Temp ORDER BY SomeString

-- desired result
SELECT * FROM #Temp 
ORDER BY LEFT(SomeString,PATINDEX('%[0-9]%',SomeString)-1), -- alphabetical sort 
CONVERT(INT,SUBSTRING(SomeString,PATINDEX('%[0-9]%',SomeString),LEN(SomeString))) -- numerical sort

查看更多信息:http://www.essentialsql.com/use-sql-server-to-sort-alphanumeric-values/

要实现这样的 'sensible order'(请参阅声明期望的结果):

X1
X2
X10

不幸的是,如果原始字符串包含任何不以数字结尾的内容(极少数例外),这将不起作用。换句话说,在这种情况下:

INSERT INTO #Temp
SELECT 'X1'
    UNION 
SELECT 'X10'
    UNION 
SELECT 'X2'
    UNION 
SELECT 'X2a'

PS:

一个可能的粗略解决方案:

SELECT * FROM #Temp 
ORDER BY LEFT(SomeString,PATINDEX('%[0-9]',CASE WHEN SomeString LIKE '%[a-Z]' THEN SomeString + '0' ELSE SomeString END)-1), -- alphabetical sort 
CONVERT(INT,SUBSTRING(SomeString,PATINDEX('%[0-9]',CASE WHEN SomeString LIKE '%[a-Z]' THEN SomeString + '0' ELSE SomeString END),LEN(SomeString)))

假设每个值中唯一的数字构成了您要作为排序依据的数字(与末尾数字之前的数字相反,例如 X5Y10X5Y10A),那么你最好的选择是 compute/extract 在 INSERT / UPDATE 时间(很少见)的数字部分,而不是在 SELECT 时间(通常要多得多)频繁):

  1. 创建一个 UDF,dbo.ExtractNumber(),以提取字符串值的数字部分。虽然 UDF 的性能通常不太理想,但它只会在 INSERT 上执行,如果此字段可更新,则可选择在 UPDATE 上执行。

  2. 将非持久化计算列添加到名为 SortField(或其他)的 table,并定义为:

    dbo.ExtractNumber([SomeString])
    
  3. 在该非持久计算列上创建一个非聚集索引,SortField

  4. 在您的查询中,执行 ORDER BY [SortField].

给定示例数据,全部以 X 开头,这意味着字符串的字母部分不相关。如果不是这种情况,并且 alpha 部分 首先排序,然后是数字部分(作为真正的数字),那么这将需要两个 UDF 和两个非持久计算列,但仍然只有一个索引。从技术上讲,UDF 可能不需要提取 alpha 部分,因为它可以是一个简单的 SUBSTRING,从 1 开始,并使用 PATINDEX 找到第一个数字的位置以提供第三个参数SUBSTRING.