我有一个只有一列的表。该列包含带逗号分隔值的字符串。我试图从表中选择每个字符串>用逗号>分割字符串然后将结果插入到不同的表中。
我的第一张表看起来像这样:
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语句只能将值作为新行插入表中。我无法弄清楚如何将值输入到相应的列中。
如何解决我的任何一个问题的任何帮助将不胜感激。
答案 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
)