MS SQL使用分隔符拆分列值并在其他字段中更新

时间:2017-07-07 10:09:26

标签: sql-server

例如,我有一张这样的表,

ID Name
1  Apple,banana
2  Grape,Orange
3  Papaya,Jackfruit

我需要拆分(,)并在SQL

中保存
ID Name    Name2
1  Apple   banana
2  Grape   Orange
3  Papaya  Jackfruit

2 个答案:

答案 0 :(得分:2)

在SQL Server 2016之前分割字符串的最快,最可扩展的方法是编写一个分割字符串的SQLCLR方法,如this one。 SQL Server 2016引入了STRING_SPLIT函数,速度更快。

在SQL Server 2016之前为版本拆分字符串的第二种最快方法是将分离的文本转换为XML并使用XML运算符来检索单个项目。典型用法,如Aaron Bertrand's articles所示,将项目作为行返回。它可以很容易地调整为以列为单位返回项目:

declare @table table (ID int, Name nvarchar(200))
insert into @table
values
(1,'Apple,banana'),
(2,'Grape,Orange'),
(3,'Papaya,Jackfruit');


with items as (
    select 
        ID,
        xmlField= cast('<item><tag>'                            
                        + replace(Name,',','</tag><tag>')
                        + '</tag></item>' as xml) 
    from @table
)
-- Step 2: Select different tags and display them as fields
select 
    y.item.value('(tag/text())[1]','nvarchar(20)') As Name1,
    y.item.value('(tag/text())[2]','nvarchar(20)') as Name2
from items outer apply xmlField.nodes('item') as y(item)

返回:

1   Apple   banana
2   Grape   Orange
3   Papaya  Jackfruit

这首先将Name1,Name2转换为<item><tag>Name1</tag><tag>Name2</tag><item>,然后将其转换为XML并作为xmlField返回。

outer apply xmlField.nodes('item') as y(item)将此字段转换为名为y的项目表。每个字段中只存在一个item行。

最后,y.item.value('(tag/text())[1]','nvarchar(20)')将第一个标记元素的 text 提取为Name1。

这可以很容易地扩展到多个条目,或者将条目作为不同的元素返回。

必须事先知道列数。 SQL(该语言)不允许任意数量的列。如果不同的字段包含不同数量的标记,则必须将它们作为行返回。

在这种情况下,如果您的目标是SQL Server 2016或XML拆分技术的原始版本,则应使用STRING_SPLIT:

CREATE FUNCTION dbo.SplitStrings_XML
(
   @List       nvarchar(max),
   @Delimiter  nvarchar(10)
)
RETURNS TABLE WITH SCHEMABINDING
AS
   RETURN (SELECT [value] = y.i.value('(./text())[1]', 'varchar(8000)')
      FROM (SELECT x = CONVERT(XML, '<i>' 
          + REPLACE(@List, @Delimiter, '</i><i>') 
          + '</i>').query('.')
      ) AS a CROSS APPLY x.nodes('i') AS y(i));

值得检查Performance Surprises and Assumptions : STRING_SPLIT(),它会比较所有可用的字符串拆分技术,以找到最快和最可扩展的

答案 1 :(得分:0)

我们通过使用超前和滞后函数以及拆分字符串来获得结果并将结果集插入到您需要的表中

IF OBJECT_ID('tempdb..#InsertTable') IS NOT NULL
DROP TABLE #InsertTable
DECLARE @table TABLE (ID INT, Name VARCHAR(50))

CREATE TABLE #InsertTable (ID INT,Name1 VARCHAR(100),Name2 VARCHAR(100))

INSERT INTO @table
SELECT 1,'Apple,Banana'  UNION ALL
SELECT 2,'Grape,Orange'  UNION ALL
SELECT 3,'Papaya,Jackfruit'

INSERT INTO #InsertTable(ID,Name1,Name2)
SELECT  DISTINCT ID,
        ISNULL(Name1,LagName1) AS Name1 ,
        ISNULL(Name2,LeadName2) AS Name2 

FROM
(
SELECT ID,
Name1,
LAG(NAme1,1)OVER(ORDER BY ID) LagName1,
Name2,
LEAD(Name2,1)OVER(ORDER BY ID)LeadName2
FROM
(
SELECT ID,   CASE WHEN Seq%2=1 THEN Name END AS Name1,
             CASE WHEN Seq%2=0 THEN Name END AS Name2  
 FROM
(
SELECT Row_NUmber ()OVER(ORDER BY ID )AS Seq,ID, Split.a.value('.', 'VARCHAR(1000)') AS Name
            FROM  (
                SELECT ID,  CAST('<S>' + REPLACE(Name, ',', '</S><S>') + '</S>' AS XML) AS Name
                FROM @table
                ) AS A
            CROSS APPLY Name.nodes('/S') AS Split(a) 

)Dt
)DT2
)Final


SELECT * FROM #InsertTable

结果

ID  Name1   Name2
----------------------
1   Apple   Banana
2   Grape   Orange
3   Papaya  Jackfruit