将多个字符串拆分为多个列

时间:2014-12-03 06:22:17

标签: sql-server string sql-server-2008-r2 split

我有以下三个不同的字符串,需要分成三个不同的列。

示例

字符串1:

Declare @str1 varchar(max) = 'A1,A2,A3'

字符串2:

Declare @str2 varchar(max) = 'B1,B2,B3'

字符串3:

Declare @str2 varchar(max) = 'C1,C2,C3'

注意我想将上述三个字符串存储在三个不同的列中。

预期输出

colA   colB   colC
------------------
A1     B1     C1
A2     B2     C2
A3     B3     C3

尝试:

SQL小提琴http://sqlfiddle.com/#!3/d41d8/41345

4 个答案:

答案 0 :(得分:2)

我知道它有点重,但它会起作用

Declare @str1 varchar(max) = 'A1,A2,A3'
Declare @str2 varchar(max) = 'B1,B2,B3'
Declare @str3 varchar(max) = 'C1,C2,C3'

DECLARE @RowCount TINYINT
DECLARE @i        TINYINT = 0

DECLARE @Table AS TABLE

(
 colA  varchar(MAX)
,ColB varchar(MAX)
,ColC varchar(MAX)

)

SET @RowCount =  len(@str1) - len(replace(@str1, ',', ''))

WHILE(@i<=@RowCount)
BEGIN
    INSERT INTO @Table
    SELECT  LEFT(@str1,CHARINDEX(',',@str1+',',0)-1) AS colA
           ,LEFT(@str2,CHARINDEX(',',@str2+',',0)-1) AS colB
           ,LEFT(@str3,CHARINDEX(',',@str3+',',0)-1) AS colC

    SET @str1 = STUFF(@str1,1,CHARINDEX(',',@str1,0),'')
    SET @str2 = STUFF(@str2,1,CHARINDEX(',',@str2,0),'')
    SET @str3 = STUFF(@str3,1,CHARINDEX(',',@str3,0),'')

    SET @i = @i + 1

END

SELECT * FROM @Table

答案 1 :(得分:0)

如果你有三个值,那么试试这个。

DECLARE @str1 VARCHAR(max) = 'A1,A2,A3'

SELECT Parsename(Replace(@str1, ',', '.'), 3) 'FST_COL',
       Parsename(Replace(@str1, ',', '.'), 2) 'SCD_COL',
       Parsename(Replace(@str1, ',', '.'), 1) 'TRD_COL' into #temp

DECLARE @str1 VARCHAR(max) = 'A1,A2,A3',
        @sql  NVARCHAR(max),
        @loop INT,
        @cnt  INT=1

SELECT @loop = Len(@str1) - Len(Replace(@str1, ',', '')) + 1

SET @sql=' WITH Split_cols ( xmlcol)
     AS (SELECT CONVERT(XML, ''<cols><col>''
                             + Replace('''
         + @str1 + ''', '','', ''</col><col>'') + ''</col></cols>'') as xmlcol)

SELECT '

WHILE @cnt <= @loop
  BEGIN
      SET @sql+=' xmlcol.value(''/cols[1]/col['
                + CONVERT(VARCHAR(30), @cnt)
                + ']'', ''varchar(100)'') AS col'
                + CONVERT(VARCHAR(30), @cnt) + ','
      SET @cnt=@cnt + 1
  END

SET @sql=LEFT(@sql, Len(@sql) - 1)
SET @sql +=' FROM   Split_cols '

--PRINT @sql

EXEC Sp_executesql @sql 

答案 2 :(得分:0)

这将适用于任何未经编码的字符串和值

CREATE FUNCTION dbo.splitstring (@stringToSplit VARCHAR(MAX) )
RETURNS
 @returnList TABLE ([ID] INT IDENTITY(1,1),[Name] [nvarchar] (500))
AS
BEGIN

 DECLARE @name NVARCHAR(255)
 DECLARE @pos INT

 WHILE CHARINDEX(',', @stringToSplit) > 0
 BEGIN
  SELECT @pos  = CHARINDEX(',', @stringToSplit)  
  SELECT @name = SUBSTRING(@stringToSplit, 1, @pos-1)

  INSERT INTO @returnList 
  SELECT @name

  SELECT @stringToSplit = SUBSTRING(@stringToSplit, @pos+1, LEN(@stringToSplit)-@pos)
 END

 INSERT INTO @returnList
 SELECT @stringToSplit

 RETURN
END






-- USE THIS PARAMETER TO PASS VALUE
DECLARE @STRING VARCHAR(MAX)    




DECLARE @COUNT INT
DECLARE @I INT
DECLARE @COLUMNNAME VARCHAR(MAX)
DECLARE @CREATETABLE VARCHAR(MAX)
DECLARE @INSERT VARCHAR(MAX)

IF OBJECT_ID('TEMPDB..##TEMPTABLE') IS NOT NULL
    DROP TABLE ##TEMPTABLE
IF OBJECT_ID('TEMPDB..##RETURNLIST') IS NOT NULL
    DROP TABLE ##RETURNLIST
SELECT * INTO ##RETURNLIST FROM dbo.splitstring(@STRING)

select @COUNT = COUNT(*) from ##RETURNLIST
SET @I=0
SET @CREATETABLE = 'CREATE TABLE ##TEMPTABLE ('
WHILE (@COUNT>0)
BEGIN
    SET @COLUMNNAME = 'COLUMN'+ CONVERT(varchar(10), @I) + ' VARCHAR(MAX)'
    SET @CREATETABLE = @CREATETABLE + @COLUMNNAME
    IF(@COUNT<>1)
     SET @CREATETABLE = @CREATETABLE + ', '
    SET @I = @I+1
    SET @COUNT = @COUNT -1;
END
SET @CREATETABLE = @CREATETABLE + ' )'

EXECUTE(@CREATETABLE)

SET @INSERT = 'INSERT INTO ##TEMPTABLE VALUES( '
WHILE (@I>0)
BEGIN

    SET @INSERT = @INSERT +''''+ (SELECT NAME FROM ##RETURNLIST WHERE ID = @COUNT+1) +''''
    IF(@I<>1)
     SET @INSERT = @INSERT + ', '
    SET @I = @I-1
    SET @COUNT = @COUNT +1;
ENDenter code here

SET @INSERT = @INSERT + ' )'

EXECUTE(@INSERT)
EXECUTE('SELECT * FROM ##TEMPTABLE')

答案 3 :(得分:0)

您还没有给出每个列连接值的标准,所以我只是按降序加入它们。此解决方案可以处理列表中的任意数量的项目,但如果数字过高,您可能需要使用MAX RECURSION查询提示。

DECLARE @strA NVARCHAR(MAX) = 'A1,A2,A3';
DECLARE @strB NVARCHAR(MAX) = 'B1,B2,B3,B4';
DECLARE @strC NVARCHAR(MAX) = 'C1,C2,C3';

WITH stringData AS (
    --each group of comma separate values with a group identifier
    SELECT 'a' AS grp, @strA AS strng
    UNION ALL
    SELECT 'b' AS grp, @strB
    UNION ALL
    SELECT 'c' AS grp, @strC
),
splitStrings AS (
    --a recursive CTE to split the comma separated values
    SELECT grp, CAST('' AS NVARCHAR(MAX)) AS item,
        strng AS cText
    FROM stringData

    UNION ALL

    SELECT grp,
        CASE
            WHEN CHARINDEX(N',',cText,0)>0 THEN LEFT(cText,CHARINDEX(N',',cText,0)-1) --SUBSTRING(cText,0,CHARINDEX(N',',cText,0))
            ELSE cText
        END,
        RIGHT(cText,LEN(cText)-CHARINDEX(N',',cText,0))
    FROM splitStrings
    WHERE cText!=item
)
SELECT grp,
    item,
    ROW_NUMBER() OVER(PARTITION BY grp ORDER BY item) AS rnum
INTO #stringValues --put the results in a temp table so we don't need to execute the recursive CTE more than once
FROM splitStrings
WHERE len(item)>0;

DECLARE @maxNum INT = (SELECT MAX(rnum) FROM #stringValues);

--join the values together
WITH allNums AS (
    SELECT 1 AS num

    UNION ALL

    SELECT num+1
    FROM allNums
    WHERE num<@maxNum
)
SELECT sa.item AS colA,
    sb.item AS colB,
    sc.item AS colC
FROM allNums
LEFT JOIN #stringValues AS sa ON sa.rnum=allNums.num AND sa.grp='A'
LEFT JOIN #stringValues AS sb ON sb.rnum=allNums.num AND sb.grp='B'
LEFT JOIN #stringValues AS sc ON sc.rnum=allNums.num AND sc.grp='C'

DROP TABLE #stringValues;