需求:將縱向儲存的資料(如:年份、月份、銷售額)轉為橫向報表(年份為行,月份為列),即經典的行列轉換 / 透視查詢。本文介紹標準 SQL 與各主流資料庫的實作語法。
-- 原始表 sales
Year | Month | Amount
2023 | 1 | 1000
2023 | 2 | 1200
2023 | 3 | 1100
2024 | 1 | 1300
2024 | 2 | 1400
Year | Jan | Feb | Mar | ...
2023 | 1000| 1200| 1100| ...
2024 | 1300| 1400| 0 | ...
SELECT Year,
SUM(CASE WHEN Month = 1 THEN Amount ELSE 0 END) AS Jan,
SUM(CASE WHEN Month = 2 THEN Amount ELSE 0 END) AS Feb,
SUM(CASE WHEN Month = 3 THEN Amount ELSE 0 END) AS Mar
FROM sales
GROUP BY Year;
優點:ANSI SQL 相容、所有資料庫通用。缺點:月份固定需硬編碼。
| 資料庫 | 語法關鍵字 | 範例 |
|---|---|---|
| SQL Server | PIVOT | SELECT * FROM sales PIVOT (SUM(Amount) FOR Month IN ([1],[2],[3])) AS pvt |
| Oracle | PIVOT | SELECT * FROM sales PIVOT (SUM(Amount) FOR Month IN (1 AS Jan, 2 AS Feb)) |
| PostgreSQL | crosstab (tablefunc 擴充) | SELECT * FROM crosstab('SELECT Year, Month, Amount FROM sales') AS ct(Year int, Jan int, Feb int, Mar int) |
| MySQL | 無原生 PIVOT,用 CASE 或動態 SQL | 同標準 SQL;動態列需預處理語句構建 |
| SQLite | CASE 聚合 | 同標準 SQL |
若月份不固定,需動態生成 SQL:
PREPARE/EXECUTE 或 sp_executesql)。-- SQL Server
SELECT Year, Month, Amount
FROM pvt_table
UNPIVOT (Amount FOR Month IN (Jan, Feb, Mar)) AS upvt;
提問者回饋:「這就叫做透視變換 自己谷歌下」。掌握 CASE聚合 通用寫法,再依資料庫優化為原生 PIVOT,即可應對大多數報表轉換需求。