将多个字符串拆分为多列
Posted
技术标签:
【中文标题】将多个字符串拆分为多列【英文标题】: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
【问题讨论】:
之前询问了无数次。请尝试搜索.... @MitchWheat OP 询问了如何拆分并将其转换为列 你的意思是这样的:***.com/questions/27250433/… 【参考方案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
。
好的!但正如我所说,价值观是动态的。我怎么会在这里手动知道每个值的索引值。
我们可以用同样的方法吗:***.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;
【讨论】:
以上是关于将多个字符串拆分为多列的主要内容,如果未能解决你的问题,请参考以下文章
Pandas使用str属性获取数据列的字符串方法类split函数基于指定分隔符拆分数据列的内容为列表设置参数n控制拆分的次数设置expand参数将拆分结果列表内容转化为多列dataframe
Pandas使用split函数基于指定分隔符拆分数据列的内容为列表设置expand参数将拆分结果列表内容转化为多列数据并添加到原数据中replace函数基于正则表达式替换字符串数据列中的匹配内容