Sql server 使用混合字母数字数据对varchar字段进行排序
我在这里搜索并阅读了很多答案,但找不到一个能回答我问题的答案(或者帮助我自己找到答案) 我们有一个包含varchar显示字段的表,客户输入谁的数据。 当我们显示结果时,我们的客户希望“正确”订购结果 数据可能的示例如下所示:Sql server 使用混合字母数字数据对varchar字段进行排序,sql-server,tsql,sql-server-2012,Sql Server,Tsql,Sql Server 2012,我在这里搜索并阅读了很多答案,但找不到一个能回答我问题的答案(或者帮助我自己找到答案) 我们有一个包含varchar显示字段的表,客户输入谁的数据。 当我们显示结果时,我们的客户希望“正确”订购结果 数据可能的示例如下所示: "AAA 2 1 AAA" "AAA 10 1 AAA" "AAA 10 2 BAA" "AAA 101 1 AAA" "BAA 101 2 BBB" "BAA 101 10 BBB" "BAA 2 2 AAA" 按此列排序ASC返回: 1: "AAA 10 1 AAA"
"AAA 2 1 AAA"
"AAA 10 1 AAA"
"AAA 10 2 BAA"
"AAA 101 1 AAA"
"BAA 101 2 BBB"
"BAA 101 10 BBB"
"BAA 2 2 AAA"
按此列排序ASC返回:
1: "AAA 10 1 AAA"
2: "AAA 10 2 BAA"
3: "AAA 101 1 AAA"
4: "AAA 2 1 AAA"
5: "BAA 101 10 BBB"
6: "BAA 101 2 BBB"
7: "BAA 2 2 AAA"
客户希望第4行实际上是第一行(因为第2行在第10行之前),类似地,第7行在第4行和第5行之间,如下所示:
1: "AAA 2 1 AAA"
2: "AAA 10 1 AAA"
3: "AAA 10 2 BAA"
4: "AAA 101 1 AAA"
5: "BAA 2 2 AAA"
6: "BAA 101 10 BBB"
7: "BAA 101 2 BBB"
现在,真正棘手的一点是,对于本专栏中的数据,没有硬性规定;这完全取决于客户在这里输入了什么(上面显示的数据只是为了证明问题的任意性)
有什么帮助吗
编辑:
得知这被称为“自然排序”,我的搜索结果得到了极大的改善
我将对这个问题给出一个公认的答案,并将相应地更新:
- 如果没有一致性,你只有蛮力
- 没有规则,你的暴力是有限的
DECLARE @t table (
a varchar(50)
);
INSERT INTO @t (a)
VALUES ('AAA 2 1 AAA')
, ('AAA 10 1 AAA')
, ('AAA 10 2 BAA')
, ('AAA 101 1 AAA')
, ('BAA 101 2 BBB')
, ('BAA 101 10 BBB')
, ('BAA 2 2 AAA')
, ('Completely different')
;
; WITH step1 AS (
SELECT a
, CASE WHEN a LIKE '[A-Z][A-Z][A-Z] [0-9]%' THEN 1 ELSE 0 END As fits_pattern
, CharIndex(' ', a) As first_space
FROM @t
)
, step2 AS (
SELECT *
, CharIndex(' ', a, first_space + 1) As second_space
, CASE WHEN fits_pattern = 1 THEN Left(a, 3) ELSE 'ZZZ' END As first_part
, CASE WHEN fits_pattern = 1 THEN SubString(a, first_space + 1, 1000) ELSE 'ZZZ' END As rest_of_it
FROM step1
)
, step3 AS (
SELECT *
, CASE WHEN fits_pattern = 1 THEN SubString(rest_of_it, 1, second_space - first_space - 1) ELSE 'ZZZ' END As second_part
FROM step2
)
SELECT *
, Right('000' + second_part, 3) As second_part_formatted
FROM step3
ORDER
BY first_part
, second_part_formatted
, a
;
相关排序结果:
a
---------------------
AAA 2 1 AAA
AAA 10 1 AAA
AAA 10 2 BAA
AAA 101 1 AAA
BAA 2 2 AAA
BAA 101 10 BBB
BAA 101 2 BBB
Completely different
此代码可以大大改进/缩短。为了让您更清楚地了解所采取的步骤,我将其保留为详细内容。首先创建此函数
Create FUNCTION dbo.SplitAndJoin
(
@delimited nvarchar(max),
@delimiter nvarchar(100)
) RETURNS Nvarchar(Max)
AS
BEGIN
declare @res nvarchar(max)
declare @t TABLE
(
-- Id column can be commented out, not required for sql splitting string
id int identity(1,1), -- I use this column for numbering splitted parts
val nvarchar(max)
)
declare @xml xml
set @xml = N'<root><r>' + replace(@delimited,@delimiter,'</r><r>') + '</r></root>'
insert into @t(val)
select
r.value('.','varchar(max)') as item
from @xml.nodes('//root/r') as records(r)
SELECT @res = STUFF((SELECT ' ' + case when isnumeric(val) = 1 then RIGHT('00000000'+CAST(val AS VARCHAR(8)),8) else val end
FROM @t
FOR XML PATH('')), 1, 1, '')
RETURN @Res
END
GO
输入的内容似乎有一定的一致性。这表明正在输入特定的属性值,对吗?如果是这样的话,它们应该被分割成单独的字段供使用者写入,而不是单个文本字符串。但是为了解决当前的难题,我们需要一些规则来解释这些值,例如“总是以3个字符开始,然后是空格,然后是下一部分,然后是空格”。有了这些信息,你可以用锤子敲打数据,使其符合要求。恐怕不行-我们不能依赖任何一致性,这就是为什么这让我完全困惑的原因!可以肯定的是,我们只有一个varchar(100)数据字段。它可以包含数字,这些数字可以与字母字符分开。。。或者不是。当我们让客户输入他们想要的内容时,我们遇到的问题是什么/如果客户希望以某种方式对数据进行排序,那么客户需要提供如何对数据进行排序的规则。剩下的只是字符串解析。SQL恐怕没有魔法精灵灰尘。正如评论中提到的。。实际上没有模式。数据可以是1:“我希望这是第2位”,2:“我希望这是第10位”,3:“这应该是列表中的第1位”。。。然后,顺序应为3,1,2。人类的思维非常容易做出这样的顺序,而且似乎很自然地正确。。但是没有模式,否则我就不会被困在第一位了!:/@Sk93是模式,因此:“找到字符串中出现的第一个数字,并按此进行排序”?否。同样,没有模式。他们可以很容易地添加另一行“实际上,我希望这是第1行,而不是前面建议的第3行”。。然后这个会排在其他三个之前,因为字母和数字都在前面。@Sk93那么我恐怕你运气不好。计算机不是智能的。有些用户也不是;)如果他们接着加上“事实上,我希望这不是前面建议的第5行,而是第1行”,它实际上不是第一行,因为上面的前一个条目应该先出现,因为第5行高于第3行…@sk93你尝试过我的解决方案吗?
Select * from Test
order by dbo.SplitAndJoin(col1,' ')