テーブル行を「selectで行を列」に入替えたい時は、時折必要となります。
簡単な例で、そのサンプルを纏めておきます。
コンテンツ
サンプルテーブル
このテーブルのwork_dayを列とし、user_idごとのbtw_timeを上下に並べて表示します。
MySQL、PostgreSQL、Oracleなど
SELECT user_id
,max(CASE WHEN work_day = ‘2020/04/01’ THEN btw_time END) AS wd0401
,max(CASE WHEN work_day = ‘2020/04/02’ THEN btw_time END) AS wd0402
,max(CASE WHEN work_day = ‘2020/04/03’ THEN btw_time END) AS wd0403
FROM t_wok_time
GROUP BY user_id
※検証確認はMySQLのみです。
SQLServer、Accessなど
SELECT user_id
,max(iif(work_day = cdate(‘2020/04/01’), btw_time, null)) AS wd0401
,max(iif(work_day = cdate(‘2020/04/02’), btw_time, null)) AS wd0402
,max(iif(work_day = cdate(‘2020/04/03’), btw_time, null)) AS wd0403
FROM t_wok_time
GROUP BY user_id
※検証確認はAccessのみです。
「selectにselectサブクエリー」を入れる方法もありますが、列が多くなればなるほど検索コストが多くなるので、可読性は少しちますが上記方法が性能的に優位であると思います。
この方法のイメージが難しい人向けに説明しておきますと「user_idでグループ化しない」ように「ユニークとなるキーをgroup byに設定」すれば以下の表が求められるので理解しやすいのではないかと思います。
(この例では「group by user_id, work_day」)
user_idをグループし、max(btw_time)している意味が理解し易いかと思います。
集計して『行』→『列』入替え
集計する場合も「横並べしたい行を gruop化してユニーク」にしておけば、その後は考えは同じですが、おさらいしておきます。
テーブルイメージ
伝票イメージのテーブルですが「product_id」と「order_date」でグループ化し「quantity」の集計を求め「order_date」を列とした「product_id」ごとの「quantity」集計値を横に並べて上下で比較できる表を求めます。
select product_id
,max(case when order_date = ‘2020/04/01’ then sum_qty end) as od0401
,max(case when order_date = ‘2020/04/02’ then sum_qty end) as od0402
,max(case when order_date = ‘2020/04/03’ then sum_qty end) as od0403
from (
select product_id, order_date, sum(quantity) as sum_qty
from t_order
group by product_id, order_date
)odsum
group by os.product_id
下のグループ化でquantityを集計したユニークテーブルを作成し、それをproduct_idごとにグループ化しmax(sum_qty)で日付列ごとに並べると完成です。