【问题标题】:Replacing unwanted portions of a string value in SQL column替换 SQL 列中不需要的字符串值部分
【发布时间】:2018-12-09 15:05:37
【问题描述】:

我有一个如下格式的表,其中 COL1 包含唯一标识符,COL2 包含电话号码集合,后跟标签(<abc><def>)并由管道分隔(|)。每行的电话记录数量未知 - 它可能只包含一个电话号码,后跟标签或最多 10 个。

Table
----------
COL1 : COL2
----------
ID1 : 1234567890<abc>|4312314124<abc>|1232345133<def>|4131234131<abc>|41234134132<def>

我需要将此数据复制到一个新表中,结果格式如下,即删除带有标签&lt;def&gt;的字符串的所有部分。

    Table
    ----------
    COL1 : COL2
    ----------
    ID1 : 1234567890<abc>,4312314124<abc>,4131234131<abc>

为了获得最佳性能,最好的方法是什么?我需要该程序来转换包含大约一百万条记录的表中的数据。

【问题讨论】:

    标签: sql tsql ssis sql-server-2014


    【解决方案1】:

    如果性能很重要,那么我建议delimitedSplit8k_Lead。您可以只使用管道作为分隔符来拆分字符串,然后排除不以 . 结尾的项目(标记)。

    DECLARE @table TABLE (COL1 VARCHAR(10), COL2 VARCHAR(1000));
    INSERT @table
    VALUES
    ('ID1','1234567890<abc>|4312314124<abc>|1232345133<def>|4131234131<abc>|41234134132<def>'),
    ('ID2','2662314129<abc>|7868845133<abc>|6831234131<abc>|41234139999<xxx>|1234567999<abc>')
    
    SELECT t.COL1, ds.item
    FROM @table t
    CROSS APPLY dbo.DelimitedSplit8K_LEAD(t.COL2,'|') ds
    WHERE ds.Item LIKE '%<abc>';
    

    退货

    COL1       item
    ---------- -----------------
    ID1        1234567890<abc>
    ID1        4312314124<abc>
    ID1        4131234131<abc>
    ID2        2662314129<abc>
    ID2        7868845133<abc>
    ID2        6831234131<abc>
    ID2        1234567999<abc>
    

    然后您使用 XML PATH 进行连接,如下所示:

    DECLARE @table TABLE (COL1 VARCHAR(10), COL2 VARCHAR(1000));
    INSERT @table
    VALUES
    ('ID1','1234567890<abc>|4312314124<abc>|1232345133<def>|4131234131<abc>|41234134132<def>'),
    ('ID2','2662314129<abc>|7868845133<abc>|6831234131<abc>|41234139999<xxx>|1234567999<abc>')
    
    SELECT t.COL1, stripBadNumbers.newString
    FROM @table t
    CROSS APPLY 
    (VALUES((
      SELECT ds.item
      FROM dbo.DelimitedSplit8K_LEAD(t.COL2,'|') ds
      WHERE ds.Item LIKE '%<abc>'
      FOR XML PATH(''), TYPE
    ).value('.', 'varchar(1000)'))) stripBadNumbers(newString);
    

    返回:

    COL1       newString
    ---------- -------------------------------------------------------------------
    ID1        1234567890<abc>4312314124<abc>4131234131<abc>
    ID2        2662314129<abc>7868845133<abc>6831234131<abc>1234567999<abc>
    

    【讨论】:

    • 非常感谢艾伦。我会试试这个。
    【解决方案2】:

    基本上使用replace(),你的那个字符串可以很容易地转换成一些XML。然后可以使用 XQuery 选择带有正确标记的电话号码。作为奖励,这可能适用于任意数量的电话号码。

    (我没有得到你的架构,所以我使用我自己的。自己翻译成你的。)

    CREATE TABLE elbat
                 (nmuloc nvarchar(MAX));
    
    INSERT INTO elbat
                (nmuloc)
                VALUES ('1234567890<abc>|4312314124<abc>|1232345133<def>|4131234131<abc>|41234134132<def>');
    
    WITH
    cte AS
    (
    SELECT convert(xml,
                   concat('<phonenumbers><phonenumber number="', 
                   replace(replace(substring(nmuloc,
                                             1,
                                             len(nmuloc) - 1),
                                   '<',
                                   '" tag="'),
                           '>|',
                           '"/><phonenumber number="'),
                   '"/></phonenumbers>')) phonenumbers
           FROM elbat
    )
    SELECT stuff((SELECT ',' + nodes.node.value('concat(./@number, "<", ./@tag, ">")',
                                                'nvarchar(max)')
                         FROM cte
                              CROSS APPLY phonenumbers.nodes('/phonenumbers/phonenumber[@tag="abc"]') nodes(node)
                         FOR XML PATH(''),
                                 TYPE).value('(.)[1]',
                                             'nvarchar(max)'),
                 1,
                 1,
                 '');
    

    但是,当您使用它时,您应该真正考虑规范化您的架构,并且不要再在字符串中使用分隔符分隔的列表以及非原子序数和标签组合!

    SQL Fiddle

    【讨论】:

      【解决方案3】:

      一开始我没看懂你的问题,但是如果你的sql server是2016或更高版本,你可以按照代码来回答。我认为它有很好的性能

      Insert into table2 (ID1)
      SELECT 
          STUFF((SELECT [value] +N',' AS 'data()' FROM STRING_SPLIT(ID1,'|') WHERE [value] LIKE'%<abc>' FOR XML PATH(''),TYPE)
          .value('text()[1]','nvarchar(max)'),1,2,N'') AS ID1 
      FROM    
          table1
      

      【讨论】:

      • 他需要保留 数字,而不是 数字。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-27
      • 1970-01-01
      • 2020-03-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多