【问题标题】:Split multiple string's into multiple columns将多个字符串拆分为多列
【发布时间】:2014-12-03 06:22:17
【问题描述】:

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

示例

字符串 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

【问题讨论】:

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


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

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

    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 
    

    【讨论】:

    • 我想将结果插入到#temp 表中。并且字符串的值是动态的。
    • @MAK - 只需在末尾添加INTO #TEMP
    • 好的!但正如我所说,价值观是动态的。我怎么会在这里手动知道每个值的索引值。
    • 我们可以用同样的方法吗:stackoverflow.com/questions/27255512/string-into-single-column for MULTIPLE STRINGS
    • @MAK 不,你想将 CSV 转换为多行,但这里应该是多列。
    【解决方案3】:

    这将适用于任意数量的非硬编码字符串和值

    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')
    

    【讨论】:

      【解决方案4】:

      您没有给出将每行列的值连接在一起的任何标准,所以我只是按降序连接它们。此解决方案可以处理列表中任意数量的项目,但如果数量过多,您可能需要使用 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;
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-10-29
        • 1970-01-01
        • 2011-06-14
        相关资源
        最近更新 更多