代码之家  ›  专栏  ›  技术社区  ›  Anonymous Creator

在SQL中按第一个匹配数字排序,然后按第二个匹配数字排序,依此类推

  •  1
  • Anonymous Creator  · 技术社区  · 7 年前

    Btc0504
    Btc_0007_Shd_01
    Btc_007_Shd_01
    Bcd0007_Shd_7
    ptc00044
    Brg0007_Shd_6
    Btc0075_Shd
    Bcc43
    MR_Tst_etc0565
    wtc0004_Shd_4
    vtc_Btc0605
    

    wtc0004_Shd_4
    Bcc43
    ptc00044
    Btc_007_Shd_01
    Btc_0007_Shd_01
    Brg0007_Shd_6
    Bcd0007_Shd_7
    Btc0075_Shd
    Btc0504
    MR_Tst_etc0565
    Btc_vtc0605
    

    中间的字符串可以是任何数字。

    所以可以有更多带行的字符串和数字。即A1B2C3D4E5…,U7G2U9W288…

    下表给出了示例。

    http://rextester.com/IDQ22263

    5 回复  |  直到 7 年前
        1
  •  2
  •   Cetin Basoz    7 年前

    假设您最多有2个数字块,每个数字最多为10位,我为您创建了一个这样的示例clr udf(dbproject-sql clr database project):

    using System.Collections.Generic;
    using System.Data.SqlTypes;
    using System.Text.RegularExpressions;
    
    public partial class UserDefinedFunctions
    {
        [Microsoft.SqlServer.Server.SqlFunction]
        public static SqlString CustomStringParser(SqlString str)
        {
            int depth = 2; // 2 numbers at most
            int width = 10; // 10 digits at most
    
            List<string> numbers = new List<string>();
            var matches = Regex.Matches((string)str, @"\d+");
            foreach (Match match in matches)
            {
                numbers.Add(int.Parse(match.Value).ToString().PadLeft(width, '0'));
            }
            return string.Join("", numbers.ToArray()).PadRight(depth*width);
        }
    }
    

    IF EXISTS ( SELECT  *
                FROM    sys.objects
                WHERE   object_id = OBJECT_ID(N'[dbo].[ufn_MyCustomParser]') AND
                        type IN ( N'FN', N'IF', N'TF', N'FS', N'FT' ) )
      DROP FUNCTION [dbo].[ufn_MyCustomParser]
    GO
    IF EXISTS ( SELECT  *
                FROM    sys.[assemblies] AS [a]
                WHERE   [a].[name] = 'DbProject' AND
                        [a].[is_user_defined] = 1 )
      DROP ASSEMBLY DbProject;
    GO
    
    
    CREATE ASSEMBLY DbProject
    FROM 'C:\SQLCLR\DbProject\DbProject\bin\Debug\DbProject.dll'
    WITH PERMISSION_SET = SAFE;
    GO
    
    CREATE FUNCTION ufn_MyCustomParser ( @csv NVARCHAR(4000))
    RETURNS NVARCHAR(4000)
    AS EXTERNAL NAME
      DbProject.[UserDefinedFunctions].CustomStringParser;
    GO
    

    注意:SQL Server 2012(2017年有严格的安全问题需要您处理)。

    declare @MyTable table (col1 varchar(50));
    insert into @MyTable values
    ('Btc0504'),
    ('Btc0007_Shd_7'),
    ('Btc0007_Shd_01'),
    ('Btc0007_Shd_6'),
    ('MR_Tst_Btc0565'),
    ('Btc0004_Shd_4'),
    ('Btc_BwwwQAZtc0605'),
    ('Btc_Bwwwwe12541edddddtc0605'),
    ('QARTa1b2');
    SELECT * FROM @MyTable
    ORDER BY dbo.ufn_MyCustomParser(col1);
    

    输出:

    col1
    QARTa1b2
    Btc0004_Shd_4
    Btc0007_Shd_01
    Btc0007_Shd_6
    Btc0007_Shd_7
    Btc0504
    MR_Tst_Btc0565
    Btc_BwwwQAZtc0605
    Btc_Bwwwwe12541edddddtc0605
    
        2
  •  1
  •   Michał Turczyn    7 年前

    patindex

    declare @tbl table (col1 varchar(50));
    insert into @tbl values
    ('Btc0504'),
    ('Btc0007_Shd_7'),
    ('Btc0007_Shd_6'),
    ('MR_Tst_Btc0565'),
    ('Btc0004_Shd_4'),
    ('Btc_Btc0605');
    
    select col1 from (
        select col1,
               PATINDEX('%[0-9]%', col1) [startIndex],
               case PATINDEX('%[0-9][^0-9]%', col1) when 0 then LEN(col1) else     PATINDEX('%[0-9][^0-9]%', col1) end [endIndex]
        from @tbl
    ) [a]
    order by CAST(SUBSTRING(col1, startIndex, endIndex - startIndex + 1) as int)
    

    我提出了另一个解决方案,它非常紧凑,而且更一般:

    ;with cte as (
        select 1 [n], col1, STUFF(col1, PATINDEX('%[^0-9]%', col1), 1, '.') refined_col1 from @tbl
        union all
        select n+1, col1, STUFF(refined_col1, PATINDEX('%[^0-9.]%', refined_col1), 1, '.') from cte
        where n < 100 -- <--this number must be greater than the greatest amount of non-digits in a col1, this way, you are sure that you'll remove all unnecesary characters
    )
    
    select col1, refined_col1 from cte
    where PATINDEX('%[^0-9.]%', refined_col1) = 0
    order by CAST(replace(refined_col1, '.', '') as int)
    option (maxrecursion 0)
    
        3
  •  0
  •   Tim Biegeleisen    7 年前

    也就是说,一个解决方法是使用基本的字符串操作来提取两个您希望用于排序的组件。请注意,我们必须将它们强制转换为数字,否则它们将无法作为文本正确排序。

    从条目 charindex('shd_uu',entry)+4, 否则1结束;

    e查询中的条目,用于排序等,然后考虑将它们存储在单独的真实列中。

    SELECT *
    FROM entries
    ORDER BY
        CAST(SUBSTRING(entry, PATINDEX('%Btc[0-9]%', entry) + 3, 4) AS INT),
        CASE WHEN CHARINDEX('Shd_', entry) > 0
             THEN
             CAST(SUBSTRING(entry,
                            CHARINDEX('Shd_', entry) + 4,
                            LEN(entry) - CHARINDEX('Shd_', entry) -4) AS INT)
             ELSE 1 END;
    

    enter image description here

    Demo

        4
  •  0
  •   DhruvJoshi    7 年前

    您可以使用计数表/数字表来获取每个字符,只查找数字,然后组合数字以形成字符串(可以强制转换为bigint)。然后您可以根据这个字符串进行订购。

    See working demo

    ; with numbers as (
        select top 10000
            r= row_number() over( order by (select null))
        from sys.objects o1 
            cross join sys.objects o2
       )
    
    , onlynumbers as
    (
        select * from t 
        cross apply
        ( select part =substring(num,r,1),r
          from numbers where r<=len(num)
         )y
        where part  like '[0-9]' 
    )
    
    , finalorder as
    (
        select num,cast(replace(stuff
        ((
            select ','+part
            from onlynumbers o2 
            where o2.num=o1.num
            order by o2.r
            for xml path('')
            ),1,1,''),',','') as bigint) b
      from onlynumbers o1
      group by num
       )
     select num from finalorder order by b asc
    
        5
  •  0
  •   ahmed abdelqader    7 年前

    性能方面,您应该修复数据的根本原因。

    CREATE FUNCTION dbo.udf_ExtratcNumbersOnly
    (@string VARCHAR(256))
    RETURNS int
    AS
    BEGIN
        WHILE PATINDEX('%[^0-9]%',@string) <> 0
        SET @string = STUFF(@string,PATINDEX('%[^0-9]%',@string),1,'')
        RETURN cast (@string as int)
    END
    GO
    

    然后将其用作下一个:

    declare @MyTable table (col1 varchar(50));
    insert into @MyTable values
    ('Btc0504'),
    ('Btc0007_Shd_7'),
    ('Btc0007_Shd_6'),
    ('MR_Tst_Btc0565'),
    ('Btc0004_Shd_4'),
    ('Btc_BwwwQAZtc0605'),
    ('Btc_Bwwwwe12541edddddtc0605'),
    ('QARTa1b2c3d4e5');
    
    select * from @MyTable 
    order by (dbo.udf_ExtratcNumbersOnly(col1))
    

    Btc0004_Shd_4
    Btc0007_Shd_6
    Btc0007_Shd_7
    Btc0504
    MR_Tst_Btc0565
    Btc_BwwwQAZtc0605
    QARTa1b2c3d4e5
    Btc_Bwwwwe12541edddddtc0605
    

    Demo.