sql自然排序,字符串与一个标签中的数字混合

时间:2016-02-15 09:29:28

标签: sql string tsql numbers sql-order-by

我遇到了使用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可能就像任何字符组合一样。 问题是在名称中找到数字,如果可以按这些数字排序,那么可以通过其他字符进行排序......

3 个答案:

答案 0 :(得分:1)

您可以将[LABEL]列子列化为不同的列,然后按这些列排序。由于首先对null进行排序,因此对于具有较少字符的值,您不需要执行任何额外操作。

您也可以遵循此thread here

在此解决方案中,逻辑是: -

  1. 如果ID是数字,请在ID值前添加21'0并获取最后20个字符。

  2. 如果ID不是数字,请在ID值的末尾添加21'并获取前20个字符。

  3. 或者这是查询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_