查看本文中的 2 个选项:https://www.sqlshack.com/multiple-options-to-transposing-rows-into-columns/
如果使用 TSQL,您可以使用 TRANSPOSE 语句。或者,您可以使用游标/循环和动态 SQL 创建结果集。
全动态解决方案
我不敢相信我敲定了这个...也许我这样做只是为了看看我是否可以。它又长又复杂,并且使用了几个循环。我认为你应该重新评估你正在尝试做的事情。这不能在视图中运行。您将不得不放入一个函数或存储过程。您可能需要评估临时表名称以查看它们是否与您的环境兼容。此外,由于临时表名称不是唯一的,因此您不能运行多个实例;如果要运行多个实例,则必须将唯一标识符添加到临时表中的列或临时表名称。这是完全动态的……您不必提前知道需要多少列。
--**************************************************
--Header area... sample data and temp tables.
--**************************************************
--Clean up sample and result tables if they exist.
IF OBJECT_ID(N'tempdb..#T1') IS NOT NULL
DROP TABLE #T1;
IF OBJECT_ID(N'tempdb..#ResultsTemp') IS NOT NULL
DROP TABLE #ResultsTemp;
IF OBJECT_ID(N'tempdb..#codeTable') IS NOT NULL
DROP TABLE #codeTable;
--For Debugging.
DECLARE @debug int = 1; --0=no debug, 1=show debug messages, do not exec all SQL statements.
--Table var to hold sample data.
CREATE TABLE #T1 (
SampleCode nvarchar(50),
[Name] nvarchar(50),
Content nvarchar(50),
row_num int
);
--Load Sample Data.
INSERT INTO #T1 (SampleCode, [Name], Content)
VALUES
('#', '1', 'A#')
, ('#', '2', 'B#')
, ('#', '3', 'C#')
, ('@', '1', 'A@')
, ('@', '2', 'B@')
, ('@', '3', 'C@')
;
--**********END HEADER**********
--Number the rows so we can loop over them.
UPDATE #T1
SET row_num = newT1.row_num
FROM
(
SELECT t12.SampleCode
, t12.[Name]
, T12.Content
, ROW_NUMBER()OVER(ORDER BY SampleCode, [Name], Content) as row_num
FROM #T1 as t12
) AS newT1
WHERE #T1.SampleCode = newT1.SampleCode
AND #T1.[Name] = newT1.[Name]
AND #T1.Content = newT1.Content
;
SELECT * FROM #T1; --Debugging... just show the contents of #T1 after adding row_num
--Create temp table to load results.
CREATE TABLE #ResultsTemp (
Column1 nvarchar(50)
);
--Create some variable to track looping (without a cursor).
DECLARE @loopCount int = 1;
DECLARE @maxLoops int = (SELECT COUNT(DISTINCT SampleCode) FROM #T1);
DECLARE @sql nvarchar(512);
--Add columns to #ResultsTable dynamically
WHILE (@loopCount <= (@maxLoops))
BEGIN
SET @sql = 'ALTER TABLE #ResultsTemp ADD ' + QUOTENAME('Column' + CAST((@loopCount + 1) as nvarchar)) + ' nvarchar(50) NULL';
IF (@debug = 1) PRINT @sql;
EXEC (@sql);
SET @loopCount = @loopCount + 1;
END
--************************************************************
--SECTION FOR INSERTING FIRST ROW for "SampleCode"
--************************************************************
--Vars for tracking the SampleCode variations processed.
DECLARE @sampleLoop int = 1;
DECLARE @sampleCount int = (SELECT COUNT(DISTINCT SampleCode) FROM #T1);
CREATE TABLE #codeTable (
SampleCode nvarchar(50)
, row_num int
);
--Create a list of unique SampleCodes to loop over.
INSERT INTO #codeTable (SampleCode)
SELECT DISTINCT
SampleCode
FROM #T1;
UPDATE #codeTable
SET row_num = newCT.row_num
FROM
(
SELECT ct2.SampleCode
, ROW_NUMBER()OVER(ORDER BY SampleCode) as row_num
FROM #codeTable as ct2
) AS newCT
WHERE #codeTable.SampleCode = newCT.SampleCode
;
SET @sql = 'INSERT INTO #ResultsTemp (Column1) SELECT ''SampleCode''';
IF (@debug = 1) PRINT @sql;
EXEC (@sql);
WHILE (@sampleLoop <= @sampleCount)
BEGIN
SET @sql = 'UPDATE #ResultsTemp SET Column' + CAST(@SampleLoop + 1 as nvarchar) + '=(SELECT TOP 1 SampleCode FROM #codeTable WHERE row_num = ' + CAST(@sampleLoop as nvarchar) + ');';
IF (@debug = 1) PRINT @sql;
EXEC (@sql);
SET @sampleLoop = @sampleLoop + 1;
END
IF (@debug = 1) SELECT * FROM #ResultsTemp;
--**********END SECTION**********
--**************************************************
--SECTION FOR INSERTING THE REST OF THE CONTENT DATA
--**************************************************
--Vars for tracking number of rows processed from T1.
SET @loopCount = 1;
SET @maxLoops = (SELECT MAX(row_num) FROM #T1);
--Loop over each row in T1.
WHILE (@loopCount <= @maxLoops)
BEGIN
--Create a name for this row.
DECLARE @nameRaw nvarchar(50) = (SELECT TOP 1 [Name] FROM #T1 WHERE row_num = @loopCount);
DECLARE @codeNum nvarchar(50) = (
SELECT TOP 1 ct.row_num
FROM #T1 as t
INNER JOIN #codeTable as ct
ON ct.SampleCode = t.SampleCode
WHERE t.row_num = @loopCount);
DECLARE @name nvarchar(50) = 'Name.' + @nameRaw;
--First insert a row for this Name... if not already in the list.
SET @sql = 'INSERT INTO #ResultsTemp (Column1)
SELECT ''Name.'' + t.[Name]
FROM #T1 as t
LEFT OUTER JOIN #ResultsTemp as rt
ON rt.Column1 = ''' + @name + '''
WHERE t.row_num = ' + CAST(@loopCount as nvarchar) + '
AND rt.Column1 IS NULL;';
IF (@debug = 1) PRINT @sql;
EXEC (@sql);
--Update this Name row with the "content".
SET @sql = 'UPDATE rt
SET Column' + CAST(@codeNum + 1 as nvarchar) + '=t.Content
FROM #ResultsTemp as rt
INNER JOIN #T1 as t
ON t.row_num = ' + CAST(@loopCount as nvarchar) + '
AND t.[Name] = ''' + @nameRaw + '''
WHERE rt.Column1 = ''' + @name + ''';';
IF (@debug = 1) PRINT @sql;
EXEC (@sql);
SET @loopCount = @loopCount + 1;
END
--Show everything in the temp Results table.
SELECT *
FROM #ResultsTemp;
结果集:
静态选择解决方案
下一个选项不是动态的。您必须知道需要多少列,然后您可以将“Column3”代码复制到任何新列。您必须更改列名并更新“Select TOP 1”语句,如您要复制的每个新列的注释。
WITH CodeTable AS (
SELECT DISTINCT t.SampleCode
FROM #T1 as t
)
SELECT DISTINCT
'Name.' + [Name]
, (
SELECT TOP 1 Content
FROM #T1 as t2
WHERE t2.SampleCode = (
SELECT TOP 1 SampleCode
FROM CodeTable as ct
ORDER BY SampleCode
)
AND t2.[Name] = t.[Name]
) as Column2
, (
SELECT TOP 1 Content
FROM #T1 as t2
WHERE t2.SampleCode = (
SELECT TOP 1 SampleCode
FROM CodeTable as ct
WHERE ct.SampleCode NOT IN (
SELECT TOP 1 SampleCode --Update the TOP 1 to be TOP [number of previous columns]
FROM CodeTable as ct2
ORDER BY ct2.SampleCode
)
ORDER BY ct.SampleCode
)
AND t2.[Name] = t.[Name]
) as Column3
FROM #T1 as t
静态数据透视表解决方案
该解决方案来自我发布的链接。同样,您必须知道所需的列数,并且它没有您指定的通用列名。但是,如果您重新考虑您的输出,这是另一种解决方案。
--Use PivotTable.
SELECT *
FROM
(
SELECT [Name], Content
FROM #T1
) AS SourceTable PIVOT(MAX(Content) FOR [Content] IN([A#],
[A@]
)) AS PivotTable;