我有一个以下格式的表,其中COL1包含唯一标识符,COL2包含电话号码的集合,后跟标签(<abc>
或<def>
),并以竖线({{1 }})。每行中的电话记录数量未知-它可能只包含一个电话号码,后跟标记或最多10个。
|
我需要将此数据复制到一个新表中,其结果采用以下格式,即使用标签Table
----------
COL1 : COL2
----------
ID1 : 1234567890<abc>|4312314124<abc>|1232345133<def>|4131234131<abc>|41234134132<def>
删除字符串的所有部分。
<def>
获得最佳性能的最佳方法是什么?我需要程序来转换包含大约一百万条记录的表中的数据。
答案 0 :(得分:1)
基本上可以使用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,
'');
但是,当您使用它时,您应该真正考虑对架构进行规范化,并且不再在字符串中使用定界符分隔的列表以及非原子数和标记的组合!
答案 1 :(得分: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 :(得分:-1)
我最初不理解您的问题。但是,如果您的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