SQL読解問題(ウィンドウ関数・CTE)

ウィンドウ関数とCTEの組み合わせ。本番レベルの読解スピードを身につけます。

SQL読解の応用編。ウィンドウ関数とCTEを素早く読み解くための実践問題。

胡桃 あんず(しょんぼり) 胡桃 あんず

ウィンドウ関数のクエリ、毎回こんがらがっちゃうんだよね…

若葉 みどり 先生(笑顔) 若葉 みどり 先生

OVER句の中のPARTITION BYとORDER BYを最初に読むのがコツなのよ。 そうすれば『何で区切って・何で並べた上で・何を計算するか』が見えてくるということね。

-- ▼ 問題例1: 各カテゴリ内での売上順位
SELECT
  product_id,
  category,
  total_sales,
  ROW_NUMBER() OVER (
    PARTITION BY category
    ORDER BY total_sales DESC
  ) AS rank_in_cat
FROM product_summary;

-- 解読:
-- - category で区切り
-- - その中で total_sales 降順で並べ
-- - 1位から順に番号 (rank_in_cat=1, 2, 3, ...)

-- ▼ 問題例2: 累計と前月比
SELECT
  month,
  monthly_sales,
  SUM(monthly_sales) OVER (
    ORDER BY month
  ) AS cumulative,
  monthly_sales - LAG(monthly_sales) OVER (
    ORDER BY month
  ) AS diff_vs_prev
FROM monthly_summary
ORDER BY month;

-- 解読:
-- - SUM(...) OVER (ORDER BY ...) で累計
-- - LAG(...) で前月の値を取得
-- - 当月 - 前月 で前月比 (最初の月は NULL)
桜井 もも(普段) 桜井 もも

ROW_NUMBERとRANKとDENSE_RANKの違い、整理してほしいです〜。

白銀 ゆき(普段) 白銀 ゆき

金額が同じ2件があった場合、ROW_NUMBERは(1,2,3,4,5)で重複なし、RANKは(1,1,3,4,5)で同値同順位・次は飛ぶ、DENSE_RANKは(1,1,2,3,4)で同値同順位・連続、という違いがあります。 用途で使い分けるといいですね。

-- ▼ 問題例3: CTE で多段クエリ
WITH monthly AS (
  SELECT
    customer_id,
    DATE_TRUNC('month', ordered_at) AS month,
    SUM(amount) AS monthly_amt
  FROM orders
  GROUP BY 1, 2
),
ranked AS (
  SELECT
    *,
    RANK() OVER (PARTITION BY month ORDER BY monthly_amt DESC) AS rk
  FROM monthly
)
SELECT month, customer_id, monthly_amt
FROM ranked
WHERE rk <= 3
ORDER BY month, rk;

-- 解読:
-- 1段目 monthly: 顧客×月の売上集計
-- 2段目 ranked:  各月内の売上順位を付与
-- 最終: 各月のトップ3顧客を抽出
胡桃 あんず(笑い) 胡桃 あんず

CTEだと、段階ごとに何してるか追えるから分かりやすいね!

若葉 みどり 先生(普段) 若葉 みどり 先生

そうそう、CTEは『先に小さなブロックを定義して、最後にそれらを組み合わせる』設計なのよ。 各CTEを独立に意味づけてから全体を見ると読みやすくなるということね。

白銀 ゆき(普段) 白銀 ゆき

DS検定★では、このレベルのCTEとウィンドウ関数の組み合わせ問題が出ます。 慣れれば30秒で読み切れるようになりますよ。

確認クイズ

RANK() OVER (PARTITION BY category ORDER BY price DESC) で、同カテゴリ内に同価格が2件並んだ場合の順位はどうなるか。

  1. 1, 2, 3, 4, 5(重複なし)
  2. 1, 1, 3, 4, 5(同値同順位、次は飛ぶ)
  3. 1, 1, 2, 3, 4(同値同順位、次も連続)
  4. ランダム順
こたえを見る

正解: 2. 1, 1, 3, 4, 5(同値同順位、次は飛ぶ)

1, 1, 3, 4, 5(同値同順位、次は飛ぶ)がRANK()の挙動。 順位が1位の人が2人いれば次は3位。 重複なしならROW_NUMBER、連続させたいならDENSE_RANK を使います。

若葉みどり先生・白銀ゆき・桜井もも・胡桃あんずのイラスト。雪だるま作り

この記事の関連書籍

Amazonアソシエイトリンクを含みます。他分野は おすすめ書籍ページ へ。

この記事について

データサイエンティスト検定スタディが作成した教材です。運営について・記事の作り方

試験についてはこちらをご覧ください: データサイエンティスト協会 公式サイト

この記事を共有