ここではPIVOT句を用いたものと、CASE式を用いた方法を紹介します。
PIVOT句は簡潔かつ可読性も高いですが、現状一部のDBMS(SQL Server, Redshift, Snowflakeなど)でしか使えません。移植性を重視する場合は後者を使うのが良いでしょう。
今回使うデータ
以下のような、各支店の月間売上を持つテーブルを考えます。
| branch | sales_month | sales_amt |
|---|---|---|
| 支社A | 1 | 1000 |
| 支社A | 2 | 1200 |
| 支社A | 3 | 1100 |
| 支社A | 4 | 1300 |
| 支社B | 1 | 1900 |
| 支社B | 2 | 1950 |
| 支社B | 3 | 1980 |
| 支社B | 4 | 1020 |
| 支社C | 1 | 1500 |
| 支社C | 2 | 1400 |
| 支社C | 3 | 1450 |
| 支社C | 4 | 1550 |
行 → 列 への変換
「月」カラムを行持ちから列持ちへ変換します。まずPIVOT句から
PIVOT句
SELECT
branch AS '支社名',
[1] AS '1月',
[2] AS '2月',
[3] AS '3月',
[4] AS '4月'
FROM Sales
PIVOT (
SUM(sales_amt) FOR sales_month IN ([1], [2], [3], [4])
) as pvt
| 支社名 | 1月 | 2月 | 3月 | 4月 |
|---|---|---|---|---|
| 支社A | 1000 | 1200 | 1100 | 1300 |
| 支社B | 1900 | 1950 | 1980 | 1020 |
| 支社C | 1500 | 1400 | 1450 | 1550 |
列名に変換したい値(今回は「〇月」)を IN の後に列挙し、FOR句に指定した列(sales_month)の値が IN の各列名にマッチする行を集計します。
集計関数は FOR句の前に指定し、この間数値が新しい列の値となります。
(今回用意したデータでは IN で列挙した列名には高々1レコードだけがマッチするので、集計関数には何を使っても結果は同じです)
ちなみに、PIVOT句は派生テーブルとして扱われるのでエイリアスが必須です。
(サブクエリ等と同じ)
CASE式
SELECT
branch AS "支社名",
SUM(CASE WHEN sales_month = 1 THEN sales_amt ELSE 0 END) AS "1月",
SUM(CASE WHEN sales_month = 2 THEN sales_amt ELSE 0 END) AS "2月",
SUM(CASE WHEN sales_month = 3 THEN sales_amt ELSE 0 END) AS "3月",
SUM(CASE WHEN sales_month = 4 THEN sales_amt ELSE 0 END) AS "4月"
FROM Sales
GROUP BY branch
| 支社名 | 1月 | 2月 | 3月 | 4月 |
|---|---|---|---|---|
| 支社A | 1000 | 1200 | 1100 | 1300 |
| 支社B | 1900 | 1950 | 1980 | 1020 |
| 支社C | 1500 | 1400 | 1450 | 1550 |
CASE式が返す値はスカラなので、集計関数に含めるといった柔軟な使い方もできます。
ここでは sales_month が該当する月のときだけ sales_amt を合計しています。