我遇到了使用ORDER BY排序的问题。我发现了很多类似的问题,但没有答案符合我的需求。任务是:
我的列[LABEL]包含字符串,我希望得到这样的订单:
标签
'1'
'2'
'11R'
'11T9'
'11T10'
'RT_5'
'RT_6'
'RT_10'
'RT_10b'
'RT_10dyn'
and so on...
代替:
'1'
'11R'
'11T10'
'11T9'
'2S'
'RT_10'
'RT_10b'
'RT_10dyn'
'RT_5'
'RT_6'
标签columb可能就像任何字符组合一样。
问题是在名称中找到数字,如果可以按这些数字排序,那么可以通过其他字符进行排序......
答案 0 :(得分:1)
您可以将[LABEL]列子列化为不同的列,然后按这些列排序。由于首先对null进行排序,因此对于具有较少字符的值,您不需要执行任何额外操作。
您也可以遵循此thread here。
在此解决方案中,逻辑是: -
如果ID是数字,请在ID值前添加21'0并获取最后20个字符。
如果ID不是数字,请在ID值的末尾添加21'并获取前20个字符。
或者这是查询Sort Alphanumeric value
的更好解决方案让我们看看它是否有帮助。
答案 1 :(得分:1)
几个小时后,这里有解决方案:
我创建了一个以特定方式更改标签的功能:
输入@in中的每个NUMBER都替换为相同的数字
写在@digits字符与引导零。
例如:
@digit = 4, @in = 'aa300bb' return = '_aa0300bb_'.
@digit = 5, @in = 'aa300bb' return = '_aa00300bb_'.
@digit = 3, @in = 'a2c4e5' return = '_a002c004e005_'.
以下是功能:
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[fnMixSort]')
AND type in (N'FN', N'IF', N'TF', N'FS', N'FT'))
DROP FUNCTION [dbo].[fnMixSort]
GO
CREATE FUNCTION [dbo].[fnMixSort] (
@in NVARCHAR(250),
@digits int
) RETURNS NVARCHAR(1000) AS
BEGIN
DECLARE
@starts int,
@i int, -- position where next NUMBER starts
@j int, -- position where next NUMBER ends
@temp nvarchar(1000)
set @starts = 1
set @in = '_' + @in + '_' -- extended LABEL: protection from EMPTY input
while (1=1)
begin
select @temp = substring(@in, @starts, len(@in))
-- @i @j - start/end position of first number
SELECT @i = COALESCE( PATINDEX('%[0-9]%',@temp ), 0)
SELECT @j = COALESCE( PATINDEX('%[0-9][^0-9]%',@temp ), 0)
if @i = 0 break -- no more NUMBERs in the LABEL
-- now we PUT at posiotion=@i+@start-1 specific numbers of '0'
select @in = STUFF(@in, @i + @starts - 1, 0, REPLICATE('0', @digits-@j+@i-1))
select @starts = @starts + @i + @digits - 1
end
-- -------- return ---------
RETURN @in
END
GO
让我们创建一些表来检查功能:
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[aaaa_test]')
AND type in (N'U'))
DROP TABLE [dbo].[aaaa_test]
GO
CREATE TABLE [dbo].[aaaa_test](
Label [varchar](255) NULL
)
INSERT INTO [dbo].[aaaa_test] ([Label])
VALUES ('bb'),('aa12'),(''),('30'),('10rt'),
('12ru'),('1rt'),('9rt'),('aa8'),('aa10'),('aa'),
('12rz'),('12rt'),('9rt5'),('9_rt_10_23'),('9_rt_10_5'),('9rt12'),
('12rz34'),('12rz3'),('12rz35c'),('12rz105b'),('12rt'),('9rt5'),('9rt10'),('9rt12')
select
[label]
,dbo.fnMixSort(Label,5) as [fnMixSort_returns]
from [dbo].[aaaa_test]
order by dbo.fnMixSort(Label,5)
结果
label fnMixSort_returns
----------------------------------
1rt _00001rt_
9_rt_10_5 _00009_rt_00010_00005_
9_rt_10_23 _00009_rt_00010_00023_
9rt _00009rt_
9rt5 _00009rt00005_
9rt5 _00009rt00005_
9rt10 _00009rt00010_
9rt12 _00009rt00012_
9rt12 _00009rt00012_
10rt _00010rt_
12rt _00012rt_
12rt _00012rt_
12ru _00012ru_
12rz _00012rz_
12rz3 _00012rz00003_
12rz34 _00012rz00034_
12rz35c _00012rz00035c_
12rz105b _00012rz00105b_
30 _00030_
aa _aa_
aa8 _aa00008_
aa10 _aa00010_
aa12 _aa00012_
bb _bb_
这是我第一次在这里发帖... 希望它会帮助某人继续...
答案 2 :(得分:1)
另一种解决方案:不同的interchange_label:
/** ==========================================================
FUNCTION DESCRIPTION
-------------------------------------------------------------
Function for special sorting - natural-mix sorting.
Order by : number in word are treated as number, not as a
characters only.
So 'a2' is before 'a10' and '9R' is before '10R' ...
-------------------------------------------------------------
Function puts special prefix before each number.
If number has 1 digit -> with prefix is 0A
If number has 2 digits -> with prefix is 0B
... ... ...
If number has 16 digits -> with prefix is 0P
If number has 17 digits -> with prefix is 0PA
If number has 18 digits -> with prefix is 0PB
... ... ...
If number has 32 digits -> with prefix is 0PP
If number has 33 digits -> with prefix is 0PPA
... and so on...
For example:
aa123bb9 -> aa0C123bb0A9
**/
<强> CODE 强>
CREATE FUNCTION [dbo].[fnMixSort] ( @in NVARCHAR(1000) ) RETURNS NVARCHAR(1000) AS
BEGIN
DECLARE
@starts int,
@i int, -- position where next NUMBER starts
@j int, -- position where next NUMBER ends
@temp nvarchar(1000)
set @starts = 1
set @in = '_' + @in + '_' -- extended LABEL: protection from EMPTY input
while (1=1)
begin
select @temp = substring(@in, @starts, len(@in))
SELECT @i = COALESCE( PATINDEX('%[0-9]%',@temp ), 0)
if @i = 0 break -- no more NUMBERs in the LABEL
SELECT @j = COALESCE( PATINDEX('%[0-9][^0-9]%',@temp ), 0)
select @temp = '0' -- numbers->must still be numbers: before letters
while (@j >= @i + 16)
begin
select @j = @j - 16
select @temp = @temp + 'P'
end
select @temp = @temp + CHAR(@j - @i + 65) -- char(65) is 'A'
select @in = STUFF(@in, @i + @starts - 1, 0, @temp)
select @starts = @starts + LEN(@temp) + (LEN(@temp)-2)*16 + @j
end -- while
RETURN @in
END
GO
<强>结果:强>
1rt _0A1rt_
9_rt_10_5 _0A9_rt_0B10_0A5_
9_rt_10_23 _0A9_rt_0B10_0B23_
9rt _0A9rt_
9rt5 _0A9rt0A5_
9rt5 _0A9rt0A5_
9rt10 _0A9rt0B10_
9rt12 _0A9rt0B12_
9rt12 _0A9rt0B12_
10rt _0B10rt_
12rt _0B12rt_
12rt _0B12rt_
12ru _0B12ru_
12rz _0B12rz_
12rz3 _0B12rz0A3_
12rz34 _0B12rz0B34_
12rz105b _0B12rz0C105b_
30 _0B30_
9234567890123456123456789012345rz38c _0PO9234567890123456123456789012345rz0B38c_
12345678901234561234567890123456rz35c _0PP12345678901234561234567890123456rz0B35c_
123456789012345612345678901234561rz36c _0PPA123456789012345612345678901234561rz0B36c_
aa _aa_
aa0A _aa0A0A_
aa0b _aa0A0b_
aa8 _aa0A8_
aa10 _aa0B10_
aa12 _aa0B12_
bb _bb_