首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> SQL Server 資料庫 >> 關於SqlServer

SQL 行轉列、列轉行與動態交叉表完整實作教學

     編輯:關於SqlServer

案例一:列轉行(行轉欄,Pivot)

原始資料:學生成績明細表

namekmcj
張三語文80
張三數學86
張三英語75
李四語文78
李四數學85
李四英語78

目標結果:

姓名語文數學英語
張三808675
李四788578

靜態 Pivot(科目固定)

SELECT name,
       SUM(CASE km WHEN '數學' THEN cj END) AS 數學,
       SUM(CASE km WHEN '英語' THEN cj END) AS 英語,
       SUM(CASE km WHEN '語文' THEN cj END) AS 語文
FROM test
GROUP BY name;

動態 Pivot(科目不固定,自動產生欄位)

DECLARE @sql NVARCHAR(MAX) = N'SELECT name';

SELECT @sql += N', SUM(CASE km WHEN ' + QUOTENAME(km, '''') + N' THEN cj END) AS ' + QUOTENAME(km)
FROM (SELECT DISTINCT km FROM test) AS t;

SET @sql += N' FROM test GROUP BY name';

PRINT @sql;  -- 除錯用
EXEC sp_executesql @sql;

案例二:彙總統計列轉行

原始資料:

cardnosexage
1男12
2男10
3女14
4女18
5男20

目標:依性別計算平均年齡,呈現為欄位

男女
1416

動態 SQL 實作

DECLARE @sql NVARCHAR(MAX) = N'SELECT ';

SELECT @sql += N'SUM(CASE sex WHEN ' + QUOTENAME(sex, '''') + N' THEN avg_age END) AS ' + QUOTENAME(sex) + N','
FROM (SELECT sex, AVG(age) AS avg_age FROM t GROUP BY sex) AS a;

SET @sql = LEFT(@sql, LEN(@sql) - 1) + N' FROM (SELECT sex, AVG(age) AS avg_age FROM t GROUP BY sex) AS a';

EXEC sp_executesql @sql;

案例三:行轉列

原始資料:寬表(一列多欄位)

CREATE TABLE t1 (a INT, b INT, c INT, d INT, e INT, f INT, g INT);
INSERT INTO t1 VALUES (1,2,3,4,5,6,7);

目標:轉為長表(每欄位一列)

col_namecol_value
a1
b2
c3
d4
e5
f6
g7

UNION ALL 靜態寫法

SELECT 'a' AS col_name, a AS col_value FROM t1 UNION ALL
SELECT 'b', b FROM t1 UNION ALL
SELECT 'c', c FROM t1 UNION ALL
SELECT 'd', d FROM t1 UNION ALL
SELECT 'e', e FROM t1 UNION ALL
SELECT 'f', f FROM t1 UNION ALL
SELECT 'g', g FROM t1;

動態 UNPIVOT(SQL 2005+)

SELECT col_name, col_value
FROM t1
UNPIVOT (col_value FOR col_name IN (a,b,c,d,e,f,g)) AS u;

跨資料庫通用動態行轉列(利用系統目錄)

DECLARE @cols NVARCHAR(MAX), @sql NVARCHAR(MAX);

SELECT @cols = STRING_AGG(QUOTENAME(name), ',')  -- SQL 2017+
FROM sys.columns
WHERE object_id = OBJECT_ID('t1');

SET @sql = N'SELECT col_name, col_value FROM t1 UNPIVOT (col_value FOR col_name IN (' + @cols + N')) AS u';
EXEC sp_executesql @sql;

進階技巧:多欄位交叉表

若需同時依「年級」與「科目」交叉顯示「平均分數」與「及格率」,可結合 GROUPING SETS、CUBE、ROLLUP 或多層 CASE 運算,或使用報表工具(SSRS、Power BI)呈現更靈活。

效能與維護建議

  • 靜態優於動態:欄位固定時優先用靜態 SQL,有執行計畫快取、免 SQL 注入風險、除錯容易。
  • 動態 SQL 防注入:務必使用 QUOTENAME、sp_executesql 參數化,避免直接拼接字串。
  • 大量資料慎用:Pivot/Unpivot 涉及掃描與聚合,百萬列以上建議預先彙總至摘要表,或使用 Columnstore 索引加速。
  • 文件化:動態 SQL 輸出結果欄位不固定,前端報表需對應處理,務必在註解說明預期欄位來源邏輯。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved