使用分隔符拆分列值并插入到不同的表中

时间:2016-09-08 22:19:36

标签: sql-server sql-server-2012

我有一个只有一列的表。该列包含带逗号分隔值的字符串。我试图从表中选择每个字符串>用逗号>分割字符串然后将结果插入到不同的表中。

我的第一张表看起来像这样:

DataString
abc,def,gh,i,jkl
mnop,qr,stu,v,wxyz

我希望数据看起来像这样:

Value1  Value2  Value3  Value4  Value5
abc       def     gh      i      jkl
mnop      qr      stu     v      wxyz

这是我到目前为止的代码:

DECLARE @valueList varchar(100)
DECLARE @pos INT
DECLARE @len INT
DECLARE @value varchar(100)
Select @valueList = DataString from [dbo].[rawdata]


set @pos = 0
set @len = 0

WHILE CHARINDEX(',', @valueList, @pos+1)>0
BEGIN
    set @len = CHARINDEX(',', @valueList, @pos+1) - @pos
    set @value = SUBSTRING(@valueList, @pos, @len)

    insert into [dbo].[tempTable] (Value1) Values (@value)    

    set @pos = CHARINDEX(',', @valueList, @pos+@len) +1
END

我对此代码有两个问题。

问题1: - 我将用于将DataString列拉入变量@valueList的select语句只是拉取表中的最后一行而不是选择所有这些。

问题2: - 我的insert into语句只能将值作为新行插入表中。我无法弄清楚如何将值输入到相应的列中。

如何解决我的任何一个问题的任何帮助将不胜感激。

2 个答案:

答案 0 :(得分:0)

因此,您的第一个问题是将一个变量分配给一个列,就像在表中一样,只会从表中的该列中拉出一行。如果您想循环浏览当前正在执行的列中的每一行,则需要使用CURSOR或类似的变体来遍历每一行。

您遇到的第二个问题是您的while语句不正确。您丢失了它的最后一个值,因为当数据字符串中没有逗号时停止。最后一个值没有逗号,因此它会跳过最后一个值。使用您当前的方法可以解决这个问题,但我建议您另外选择拆分字符串的方法。

DECLARE @myTable TABLE (datastring VARCHAR(4000));
INSERT @myTable(datastring)
VALUES ('abc,def,gh,i,jkl'),('mnop,qr,stu,v,wxyz');

DECLARE @valueList VARCHAR(4000) = '', @i INT = 1, @pos INT = 0, @len INT = 0, @value VARCHAR(100) = '';
IF OBJECT_ID('tempTable', 'U') IS NOT NULL DROP TABLE tempTable;
CREATE TABLE tempTable (OriginalDataString VARCHAR(4000), stringVal VARCHAR(255), valNum INT);

DECLARE curs CURSOR FOR
SELECT datastring
FROM @myTable;

OPEN curs;
FETCH NEXT FROM curs INTO @valueList;
WHILE @@FETCH_STATUS = 0 BEGIN
    SELECT @pos = 0, @len = 0, @i = 1;
    WHILE 1 = 1
    BEGIN
        SET @len = ISNULL(NULLIF(CHARINDEX(',', @valueList, @pos+1), 0) - @pos, LEN(@valueList));
        SET @value = SUBSTRING(@valueList, @pos, @len);

        INSERT tempTable(OriginalDataString, stringVal, valNum)
        VALUES (@valueList, @value, @i);

        IF CHARINDEX(',', @valueList, @pos+1) = 0
            BREAK;

        SET @pos = CHARINDEX(',', @valueList, @pos+@len) + 1;
        SET @i += 1;
    END
    FETCH NEXT FROM curs INTO @valueList;
END
CLOSE curs;
DEALLOCATE curs;

SELECT MAX(CASE WHEN valNum = 1 THEN stringVal END) val1
     , MAX(CASE WHEN valNum = 2 THEN stringVal END) val2
     , MAX(CASE WHEN valNum = 3 THEN stringVal END) val3
     , MAX(CASE WHEN valNum = 4 THEN stringVal END) val4
     , MAX(CASE WHEN valNum = 5 THEN stringVal END) val5
FROM tempTable
GROUP BY OriginalDataString;

这使用游标来获取表中的每个数据字符串,将每个值放入游标中,循环遍历它们以获取值(当到达字符串末尾时循环中断)然后选择val1,val2,val3 ,结果表中的val4,val5。

但是,我建议使用递归的CTE(或者更好的是你已经内置的拆分函数),而不是使用游标和while循环。

例如,

DECLARE @myTable TABLE (datastring VARCHAR(4000));
INSERT @myTable(datastring)
VALUES ('abc,def,gh,i,jkl'),('mnop,qr,stu,v,wxyz');

WITH CTE AS (
    SELECT datastring
         , SUBSTRING(datastring, 1, ISNULL(NULLIF(CHARINDEX(',', datastring), 0) - 1, LEN(datastring))) sString
         , NULLIF(CHARINDEX(',', datastring), 0) cIndex
         , 1 Lvl
    FROM @myTable T
    UNION ALL
    SELECT datastring
         , SUBSTRING(datastring, cIndex + 1, ISNULL(NULLIF(CHARINDEX(',', datastring, cIndex + 1), 0) - 1 - cIndex, LEN(datastring)))
         , NULLIF(CHARINDEX(',', datastring, cIndex + 1), 0)
         , Lvl + 1
    FROM CTE
    WHERE cIndex IS NOT NULL)
SELECT MAX(CASE WHEN Lvl = 1 THEN sString END) val1
     , MAX(CASE WHEN Lvl = 2 THEN sString END) val2
     , MAX(CASE WHEN Lvl = 3 THEN sString END) val3
     , MAX(CASE WHEN Lvl = 4 THEN sString END) val4
     , MAX(CASE WHEN Lvl = 5 THEN sString END) val5
     --, datastring OriginalDataString
FROM CTE
GROUP BY datastring;

答案 1 :(得分:0)

Declare @YourTable table (DataString varchar(250))
Insert Into @YourTable values
('abc,def,gh,i,jkl'),
('mnop,qr,stu,v,wxyz')

Select A.*
      ,Value1=B.Pos1
      ,Value2=B.Pos2
      ,Value3=B.Pos3
      ,Value4=B.Pos4
      ,Value5=B.Pos5
 From  @YourTable A
 Cross Apply (Select * from [dbo].[udf-Str-Parse-Row](A.DataString,',')) B

返回

DataString          Value1  Value2  Value3  Value4  Value5
abc,def,gh,i,jkl    abc     def     gh      i       jkl
mnop,qr,stu,v,wxyz  mnop    qr      stu     v       wxyz

然后是UDF(如果需要)

CREATE FUNCTION [dbo].[udf-Str-Parse-Row] (@String varchar(max),@Delimeter varchar(10))
--Usage: Select * from [dbo].[udf-Str-Parse-Row]('Dog,Cat,House,Car',',')
--       Select * from [dbo].[udf-Str-Parse-Row]('John Cappelletti',' ')
--       Select * from [dbo].[udf-Str-Parse-Row]('id26,id46|id658,id967','|')

Returns Table 

As

Return (
    SELECT Pos1 = xDim.value('/x[1]','varchar(250)')
          ,Pos2 = xDim.value('/x[2]','varchar(250)')
          ,Pos3 = xDim.value('/x[3]','varchar(250)')
          ,Pos4 = xDim.value('/x[4]','varchar(250)')
          ,Pos5 = xDim.value('/x[5]','varchar(250)')
          ,Pos6 = xDim.value('/x[6]','varchar(250)')
          ,Pos7 = xDim.value('/x[7]','varchar(250)')
          ,Pos8 = xDim.value('/x[8]','varchar(250)')
          ,Pos9 = xDim.value('/x[9]','varchar(250)')
    FROM (Select Cast('<x>' + Replace(@String,@Delimeter,'</x><x>')+'</x>' as XML) as xDim) A
)