明智地使用 REVERSE
、CHARINDEX
和 SUBSTRING
,可以使我们得到想要的结果。我在下面的代码中使用了希望有解释性的列名来说明正在发生的事情。
设置示例数据:
DECLARE @Invoice TABLE (
InvoiceNumber nvarchar(10)
);
INSERT @Invoice VALUES
('790711')
,('790709-1')
,('790709-11')
,('790709-21')
,('790709-212')
,('790709-2')
SELECT * FROM @Invoice
样本数据:
InvoiceNumber
-------------
790711
790709-1
790709-11
790709-21
790709-212
790709-2
以下是代码。我有一种不安的感觉,最终表达式可能可以简化。
SELECT
InvoiceNumber
,REVERSE(InvoiceNumber)
AS Reversed
,CHARINDEX('-',REVERSE(InvoiceNumber))
AS HyphenIndexWithinReversed
,SUBSTRING(REVERSE(InvoiceNumber),1+CHARINDEX('-',REVERSE(InvoiceNumber)),LEN(InvoiceNumber))
AS ReversedWithoutAffix
,SUBSTRING(InvoiceNumber,1+LEN(SUBSTRING(REVERSE(InvoiceNumber),1+CHARINDEX('-',REVERSE(InvoiceNumber)),LEN(InvoiceNumber))),LEN(InvoiceNumber))
AS AffixIncludingHyphen
,SUBSTRING(InvoiceNumber,2+LEN(SUBSTRING(REVERSE(InvoiceNumber),1+CHARINDEX('-',REVERSE(InvoiceNumber)),LEN(InvoiceNumber))),LEN(InvoiceNumber))
AS AffixExcludingHyphen
,CAST(
SUBSTRING(InvoiceNumber,2+LEN(SUBSTRING(REVERSE(InvoiceNumber),1+CHARINDEX('-',REVERSE(InvoiceNumber)),LEN(InvoiceNumber))),LEN(InvoiceNumber))
AS int)
AS AffixAsInt
,REVERSE(SUBSTRING(REVERSE(InvoiceNumber),1+CHARINDEX('-',REVERSE(InvoiceNumber)),LEN(InvoiceNumber)))
AS WithoutAffix
FROM @Invoice
ORDER BY
-- WithoutAffix
REVERSE(SUBSTRING(REVERSE(InvoiceNumber),1+CHARINDEX('-',REVERSE(InvoiceNumber)),LEN(InvoiceNumber)))
-- AffixAsInt
,CAST(
SUBSTRING(InvoiceNumber,2+LEN(SUBSTRING(REVERSE(InvoiceNumber),1+CHARINDEX('-',REVERSE(InvoiceNumber)),LEN(InvoiceNumber))),LEN(InvoiceNumber))
AS int)
输出:
InvoiceNumber Reversed HyphenIndexWithinReversed ReversedWithoutAffix AffixIncludingHyphen AffixExcludingHyphen AffixAsInt WithoutAffix
------------- ---------- ------------------------- -------------------- -------------------- -------------------- ----------- ------------
790709-1 1-907097 2 907097 -1 1 1 790709
790709-2 2-907097 2 907097 -2 2 2 790709
790709-11 11-907097 3 907097 -11 11 11 790709
790709-21 12-907097 3 907097 -21 21 21 790709
790709-212 212-907097 4 907097 -212 212 212 790709
790711 117097 0 117097 0 790711
请注意,实际上您只需要
ORDER BY
子句,其余部分仅用于展示我的工作方式,具体如下:
- 反转字符串,找到连字符,获取连字符后的子字符串,再次反转该部分:这是没有任何词缀的数字
- (没有任何词缀的数字)的长度告诉我们要从开头删除多少个字符才能得到包括连字符在内的词缀。再删除一个字符就可以得到只有数字部分,并将其转换为
int
。幸运的是,在SQL Server中,这种转换会将空字符串转换为零。
- 最后,得到这两个部分后,我们简单地
ORDER BY
(没有任何词缀的数字),然后按(词缀的数值)排序。这就是我们要寻找的最终顺序。
如果SQL Server允许我们说SUBSTRING(value, start)
来获取从那一点开始的字符串,代码会更加简洁,但它不允许,所以我们不得不经常说SUBSTRING(value, start, LEN(value))
。