我有一个表,其中包含1列。每个条目都有一个X号分隔符。我想使用定界符将其拆分为X + 1列,然后将其插入另一个已创建的表中,该表包含x + 1列但不包含任何条目。
例如,对于表1 第1列
1,2,3,4
a,b,c,d
所以我想在表2中插入以下内容(表中已经有正确的列数)
column1 column2 column3 column4
1 2 3 4
a b c d
我对此有一个解决方案,但是它效率太低(大约花5分钟才能完成10列)。
首先,我向表1添加一个行号并填充它,然后向表2添加一个行号列,然后将表2中的所有行号插入表1。
然后我将运行以下循环:
DECLARE @DELIMITER NVARCHAR(10) = ',',
@columns nvarchar(max) ='Column1,column2,column3,column4',
@SQL NVARCHAR(MAX),
@table nvarchar(100) = 'dbo.test'
WHILE (1=1)
BEGIN
IF(@columns LIKE '%' +@DELIMITER +'%')
BEGIN
SET @SQL = 'UPDATE A
SET A.[' +SUBSTRING(@columns,0,CHARINDEX(@DELIMITER,@columns)) +'] =SUBSTRING(B.FULLTABLE,0,CHARINDEX('''+@DELIMITER+''',B.FULLTABLE))
FROM ' + @TABLE + ' A
INNER JOIN #FULLTABLE B ON B.ROW_NUMBER = A.ROW_NUMBER
SELECT FROM #FULLTABLE'
EXEC(@SQL)
SET @columns = SUBSTRING(@columns,1+CHARINDEX(@DELIMITER,@columns),LEN(@columns))
UPDATE #FULLTABLE
SET FULLTABLE = SUBSTRING(FULLTABLE,1+CHARINDEX(@DELIMITER,FULLTABLE),LEN(FULLTABLE))
END
ELSE
BEGIN
SET @SQL = 'UPDATE A
SET A.[' +@columns +'] =B.FULLTABLE
FROM ' + @TABLE + ' A
INNER JOIN #FULLTABLE B ON B.ROW_NUMBER = A.ROW_NUMBER
SELECT FROM #FULLTABLE'
EXEC(@SQL)
BREAK
END
END
请注意,我通常不会根据我正在使用的表自动对“列”的值进行硬编码,但我只是在此处对其进行硬编码,以使自己更清楚地了解要执行的操作。
有没有更有效的方法来实现这一目标?
答案 0 :(得分:1)
将字符串转换为table的函数。如果您给@ input ='1,2,3,4' 它返回 表 值1值2值3值4 1 2 3 4
create FUNCTION [dbo].[fn_listtotable1](@input AS nVarchar(max))
RETURNS
@Result TABLE(Value1 INT,Value2 INT,Value3 INT,Value4 INT)
AS
BEGIN
DECLARE @str VARCHAR(20)
DECLARE @str1 VARCHAR(20)
DECLARE @str2 VARCHAR(20)
DECLARE @str3 VARCHAR(20)
DECLARE @ind Int
IF(@input is not null)
BEGIN
SET @ind = CharIndex(',',@input)
SET @str = SUBSTRING(@input,1,@ind-1)
SET @input = SUBSTRING(@input,@ind+1,LEN(@input)-@ind)
INSERT INTO @Result(Value1) values (@str)
SET @ind = CharIndex(',',@input)
SET @str1 = SUBSTRING(@input,1,@ind-1)
SET @input = SUBSTRING(@input,@ind+1,LEN(@input)-@ind)
update @Result
set Value2 = (@str1) where Value1=@str
SET @ind = CharIndex(',',@input)
SET @str2 = SUBSTRING(@input,1,@ind-1)
SET @input = SUBSTRING(@input,@ind+1,LEN(@input)-@ind)
update @Result
set Value3 = (@str2) where Value1=@str
SET @ind = CharIndex(',',@input)
SET @str3 = @input
update @Result
set Value4 = (@str3) where Value1=@str
END
RETURN
END
将以下内容放入循环,
insert into table1(column1, column2,column3,column4)
select * from [fn_listtotable1]( @string)
答案 1 :(得分:1)
我不清楚询问的内容,是否可以让我知道
我猜这就是你的要求。我假设您使用的是SQL Server 2016及更高版本(如果看不到下面的注释来替换string_split)
CREATE TABLE OneColumn (
MyDelimitedColumn NVARCHAR(1000)
)
INSERT INTO OneColumn (MyDelimitedColumn)
VALUES
('Col1,Col2,Col3')
, ('x,y,z')
, ('1,2,3,4,5,6')
SELECT
MyDelimitedColumn,
DENSE_RANK() OVER (ORDER BY MyDelimitedColumn) as RowKey,
ROW_NUMBER() OVER (PARTITION BY MyDelimitedColumn ORDER BY MyDelimitedColumn) as ColumnKey,
value as ColValue
FROM OneColumn
CROSS APPLY string_split(MyDelimitedColumn,',')
这将导致
MyDelimitedColumn|RowKey|ColumnKey|ColValue
1,2,3,4,5,6 |1 |1 |1
1,2,3,4,5,6 |1 |2 |2
1,2,3,4,5,6 |1 |3 |3
1,2,3,4,5,6 |1 |4 |4
1,2,3,4,5,6 |1 |5 |5
1,2,3,4,5,6 |1 |6 |6
a,b,c,d,e |2 |1 |a
a,b,c,d,e |2 |2 |b
a,b,c,d,e |2 |3 |c
a,b,c,d,e |2 |4 |d
a,b,c,d,e |2 |5 |e
x,y,z |3 |1 |x
x,y,z |3 |2 |y
x,y,z |3 |3 |z
一旦获得了以上结果集,就可以进行动态透视将行转换为列。
如果您使用的是SQL Server的旧版本,只需实现这些string_split
等效功能中的任何一个
完整示例
IF OBJECT_ID('tempdb..#ResultSet') IS NOT NULL
DROP TABLE #ResultSet
IF OBJECT_ID('tempdb..#OneColumn') IS NULL
CREATE TABLE #OneColumn (
MyDelimitedColumn NVARCHAR(1000)
)
TRUNCATE TABLE #OneColumn
INSERT INTO #OneColumn (MyDelimitedColumn)
VALUES
('Col1,Col2,Col3')
, ('x,y,z')
, ('1,2,3,4,5,6')
SELECT
MyDelimitedColumn,
DENSE_RANK() OVER (ORDER BY MyDelimitedColumn) as RowKey,
ROW_NUMBER() OVER (PARTITION BY MyDelimitedColumn ORDER BY MyDelimitedColumn) as ColumnKey,
value as ColValue
INTO #ResultSet
FROM #OneColumn
CROSS APPLY string_split(MyDelimitedColumn,',')
DECLARE @MaxRowKey INT ,
@I INT = 1 ,
@DySQL NVARCHAR(MAX) ,
@PivotCols NVARCHAR(MAX)
SELECT @MaxRowKey= MAX(RowKey) FROM #ResultSet
WHILE @I <= @MaxRowKey
BEGIN
-- REPLACE STRING_AGG with FOR_XML PATH Method (https://www.red-gate.com/simple-talk/sql/t-sql-programming/concatenating-row-values-in-transact-sql/)
SET @PivotCols = (SELECT DISTINCT STRING_AGG(quotename(ColumnKey),',') FROM #ResultSet WHERE RowKey = @I)
SET @DySQL = N'
SELECT pvt.*
FROM
(
SELECT * FROM
#ResultSet
WHERE RowKey = '+cast(@i as Nvarchar(100))+'
) p
PIVOT
(
MAX(P.ColValue) FOR p.ColumnKey IN ('+@PivotCols+')
) as Pvt
'
EXEC (@dysql)
SET @I = @I + 1
END