Замена ненужных частей строкового значения в столбце SQL - PullRequest
0 голосов
/ 30 июня 2018

У меня есть таблица в следующем формате, в которой COL1 содержит уникальный идентификатор, а COL2 содержит коллекцию телефонных номеров, за которыми следует тег (<abc> или <def>) и разделенный каналом (|). Количество телефонных записей в каждой строке неизвестно - оно может содержать только один номер телефона, за которым следует тег или до 10.

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

Мне нужно скопировать эти данные в новую таблицу с результатом в следующем формате, т.е. удалить всю часть строки с тегом <def>.

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

Каковы наилучшие способы сделать это, чтобы получить оптимальную производительность? Мне нужна программа для преобразования данных в таблицу, которая содержит около миллиона записей.

Ответы [ 3 ]

0 голосов
/ 01 июля 2018

Эта ваша строка может быть легко преобразована в некоторый XML, в основном используя replace(). Телефонные номера с правой меткой могут быть выбраны с помощью 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

0 голосов
/ 01 июля 2018

Если важна производительность, я бы предложил 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>
0 голосов
/ 01 июля 2018

Сначала я не понял ваш вопрос. Но для ответа вы можете использовать следующий код, если у вас 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
...