我在这里搜索并阅读了很多答案,但找不到能解答我问题的答案,(或者帮我自己找答案)。
我们有一个包含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"
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"
现在,真正的TRICKY位,对于此列中的数据,没有严格的规则;它完全取决于客户在这里放置的内容(上面显示的数据只是用来证明问题)。
任何帮助?
修改 了解这被称为"自然分选"大大改善了我的搜索结果 我将把这个问题的接受答案给予bash并相应更新: Natural (human alpha-numeric) sort in Microsoft SQL 2005
答案 0 :(得分:1)
首先创建此功能
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
此函数获取一个以空格分隔的字符串并将其拆分为单词,然后再按空格将它们连接在一起,但如果该单词为数字,则会添加8个前导零
然后你使用这个查询
Select * from Test
order by dbo.SplitAndJoin(col1,' ')
答案 1 :(得分:0)
我已经用这段代码做了一些假设:如果它以3个字母字符开头,那么一个空格,一个数字(最多3个数字),让我们区别对待它。
这没什么特别的 - 只是字符串操作被强行赐给你&#34;某事&#34;。希望它能说明如果没有一致性和规则会有多痛苦!
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
此代码可以大大改进/缩短。我只是把它弄得很冗长,以便让你清楚地了解所采取的措施。