这个问题可以在不需要临时表、视图、循环或xml的情况下解决。首先,您可以根据下面的示例创建一个基于计数表的字符串拆分函数:
ALTER FUNCTION [dbo].[SplitString]
(
@delimitedString VARCHAR(MAX),
@delimiter VARCHAR(255)
)
RETURNS TABLE
WITH SCHEMABINDING AS
RETURN
WITH E1(N) AS ( SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1),
E2(N) AS (SELECT 1 FROM E1 a, E1 b),
E4(N) AS (SELECT 1 FROM E2 a, E2 b),
E42(N) AS (SELECT 1 FROM E4 a, E2 b),
cteTally(N) AS (SELECT 0 UNION ALL SELECT TOP (DATALENGTH(ISNULL(@delimitedString,1)))
ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E42),
cteStart(N1) AS (SELECT t.N+1 FROM cteTally t
WHERE (SUBSTRING(@delimitedString,t.N,1) = @delimiter OR t.N = 0))
SELECT ROW_NUMBER() OVER (ORDER BY s.N1) AS Nr
,Item = SUBSTRING(@delimitedString, s.N1, ISNULL(NULLIF(CHARINDEX(@delimiter,@delimitedString,s.N1),0)-s.N1,8000))
FROM cteStart s;
首先使用分割函数根据行分隔符拆分字符串。然后在每行上再次使用分割函数,使用OUTER APPLY语句。最后进行数据透视。由于列数未知,查询必须作为动态SQL执行,如下所示:
DECLARE @source VARCHAR(max) = 'A1,B1,C1,D1,E1,F1,G1;A2,B2,C2,D2,E2,F2,G2;A3,B3,C3,D3,E3,F3,G3;A4,B4,C4,D4,E4,F4,G4;A5,B5,C5,D5,E5,F5,G5;A6,B6,C6,D6,E6,F6,G6;A7,B7,C7,D7,E7,F7,G7;A8,B8,C8,D8,E8,F8,G8;A9,B9,C9,D9,E9,F9,G9;A10,B10,C10,D10,E10,F10,G10;A11,B11,C11,D11,E11,F11,G11;A12,B12,C12,D12,E12,F12,G12;A13,B13,C13,D13,E13,F13,G13;A14,B14,C14,D14,E14,F14,G14;A15,B15,C15,D15,E15,F15,G15;A16,B16,C16,D16,E16,F16,G16;A17,B17,C17,D17,E17,F17,G17;A18,B18,C18,D18,E18,F18,G18;A19,B19,C19,D19,E19,F19,G19;A20,B20,C20,D20,E20,F20,G20'
DECLARE @firstRow VARCHAR(max) = LEFT(@source, CHARINDEX(';', @source) - 1);
DECLARE @columnNames NVARCHAR(MAX) = '';
SELECT @columnNames = STUFF((
SELECT ',' + QUOTENAME(CAST(ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS VARCHAR(10)))
FROM [dbo].[SplitString](@firstRow, ',') Items
FOR XML PATH('')), 1, 1, '');
DECLARE @pivotQuery NVARCHAR(MAX) ='
;WITH CTE_SplitData AS
(
SELECT R.Nr AS [Row]
,C.[Columns]
,ROW_NUMBER() OVER (PARTITION BY R.Nr ORDER BY R.Item) AS ColumnNr
FROM [dbo].[SplitString](@source, '';'') R
OUTER APPLY (
SELECT Item AS [Columns]
FROM [dbo].[SplitString](R.Item, '','')
) C
)
-- Pivoted reuslt
SELECT * FROM
(
SELECT *
FROM CTE_SplitData
)as T
PIVOT
(
max(T.[Columns])
for T.[ColumnNr] in (' + @columnNames + ')
) as P'
EXEC sp_executesql @pivotQuery,
N'@source VARCHAR(MAX)',
@source = @source;
select * into table
的方式插入会比insert into table select * ...
更方便,因为第一种方式更加便捷。请参见我的回答中的进一步说明。 - Przemyslaw Remin