將「行存儲」的明細數據(如:學生-科目-分數)轉為「列存儲」的寬表(學生-語文-數學-英語),且列名(科目)由數據動態決定。
| 模式 | 列名來源 | 核心技術 | 優點 | 缺點 |
|---|---|---|---|---|
| 靜態 SQL 拼接 | 硬編碼 | CASE 聚合 | 簡單、無動態 SQL 風險 | 列固定、維護難 |
| 動態 SQL 拼接 | 運行時查詢 | FOR XML PATH + 執行動態 SQL | 列動態、兼容舊版本 | 注入風險、調試難 |
| 靜態 PIVOT | 硬編碼 | PIVOT 運算符 | 語法清晰、優化器友好 | 列固定 |
| 動態 PIVOT (推薦) | 運行時查詢 | PIVOT + 動態列構造 | 標準語法、列動態、性能好 | 需動態 SQL 執行 |
DECLARE
@TableName SYSNAME = N'TestRows2Columns',
@GroupCol SYSNAME = N'UserName',
@PivotCol SYSNAME = N'Subject',
@ValueCol SYSNAME = N'Source',
@FilterWhere NVARCHAR(MAX) = N''; -- 可選過濾條件
-- 1. 獲取動態列清單
DECLARE @Cols NVARCHAR(MAX);
SELECT @Cols = STRING_AGG(QUOTENAME([Subject]), N',') -- SQL 2017+
FROM (SELECT DISTINCT [Subject] FROM TestRows2Columns) AS d;
-- 舊版本用 STUFF + FOR XML PATH
-- 2. 構造動態 SQL
DECLARE @SQL NVARCHAR(MAX) = N'
SELECT ' + @GroupCol + N', ' + @Cols + N'
FROM (
SELECT ' + @GroupCol + N', ' + @PivotCol + N', ' + @ValueCol + N'
FROM ' + QUOTENAME(@TableName) + N'
' + IIF(@FilterWhere = N'', N'', N'WHERE ' + @FilterWhere) + N'
) AS src
PIVOT (
SUM(' + @ValueCol + N') FOR ' + @PivotCol + N' IN (' + @Cols + N')
) AS pvt;';
-- 3. 執行
EXEC sp_executesql @SQL;
源數據
| UserName | Subject | Source |
|---|---|---|
| 張三 | 語文 | 60 |
| 李四 | 數學 | 70 |
| 王五 | 英語 | 80 |
| 王五 | 數學 | 75 |
行轉列後
| UserName | 語文 | 數學 | 英語 |
|---|---|---|---|
| 張三 | 60 | NULL | NULL |
| 李四 | NULL | 70 | NULL |
| 王五 | 57 | 75 | 80 |

GROUPING SETS / ROLLUP / CUBE