CodeGym /コース /SQL SELF /分析のための基本的なウィンドウ関数

分析のための基本的なウィンドウ関数

SQL SELF
レベル 59, レッスン 1
使用可能

始める前に、何千行もの売上テーブルを扱ってると想像してみて。君のタスクは、各カテゴリで誰がナンバーワンのセールスなのか、2番目は誰か、みたいなのを決めること。あるいは、サンプル内の全行に番号を振って順番を追いたい時もあるよね。こういうのは全部、ウィンドウ関数を使えば超簡単!

ウィンドウ関数っていうのは、SQLでデータセットの一部(これを「ウィンドウ」って呼ぶ)に対して動作する関数のこと。集約関数(例えば SUM() や AVG() みたいなやつ)は行を1つにまとめちゃうけど、ウィンドウ関数は行をそのまま残して、計算した値を追加してくれるんだ。

集約関数との違い

集約関数はデータを「圧縮」して、行をグループ化する:

SELECT department, COUNT(*)
FROM employees
GROUP BY department;

結果:部門の数だけ、ほんの数行しか返ってこない。

ウィンドウ関数と比べてみよう — こっちは行がそのまま残るけど、新しいフィールドが追加される。例えば ROW_NUMBER() みたいなやつ:

SELECT employee_name, department,
       ROW_NUMBER() OVER (PARTITION BY department ORDER BY salary DESC) AS rank_within_department
FROM employees;

これだと、元の行は全部そのままで、rank_within_department っていう追加カラムができて、各社員に部門内での番号が割り振られるよ。

基本的なウィンドウ関数

OVER() の構文

どのウィンドウ関数でも一番大事なのは、魔法の言葉 OVER()。これが、どんな「ウィンドウ」(データの範囲)で関数を動かすかを決めるんだ。OVER() の中では、グループ分け(PARTITION BY)や 並び順(ORDER BY)を指定できるよ。

基本の構文:

<ウィンドウ関数>() OVER (
   [PARTITION BY <グループ>] 
   [ORDER BY <順序>]
)

各パーツの意味:

  • PARTITION BY: 行をグループに分ける。例えば「部門ごとに分けて」みたいな感じ。
  • ORDER BY: 行の処理順を指定する。例えば「給料が高い順に社員を並べて」みたいな。

ROW_NUMBER() 関数

ROW_NUMBER() 関数は、指定した「ウィンドウ」内で1から順番に行に番号を振るよ。仮のテーブルや、レコードの順番を決めたい時に便利。

例。sales(売上)テーブル:

id product_category seller_name revenue
1 Electronics Alice 1000
2 Electronics Bob 850
3 Furniture Alice 1200
4 Furniture Charlie 1100
5 Electronics Dana 750

クエリ:

SELECT seller_name, product_category, revenue,
       ROW_NUMBER() OVER (PARTITION BY product_category ORDER BY revenue DESC) AS row_number
FROM sales;

結果:

seller_name product_category revenue row_number
Alice Electronics 1000 1
Bob Electronics 850 2
Dana Electronics 750 3
Alice Furniture 1200 1
Charlie Furniture 1100 2

どう動くか:

  1. データは product_category ごとにグループ分けされる。
  2. 各グループは revenue(売上)の降順で並べ替えられる。
  3. 各グループ内の行に番号が振られる。

RANK() 関数

RANK() 関数は、行をランキングするために使うよ。ROW_NUMBER() と違って、同じ値があるときは同じランクになるし、値がかぶった分だけランク番号が飛ぶ。

例:

SELECT seller_name, product_category, revenue,
       RANK() OVER (PARTITION BY product_category ORDER BY revenue DESC) AS rank
FROM sales;

結果:

seller_name product_category revenue rank
Alice Electronics 1000 1
Bob Electronics 850 2
Dana Electronics 750 3
Alice Furniture 1200 1
Charlie Furniture 1100 2

DENSE_RANK() 関数

DENSE_RANK() は RANK() とほぼ同じだけど、同じ値があってもランク番号が飛ばないのが違い。

例。同じ売上のレコードを追加してみる:

id product_category seller_name revenue
6 Electronics Alice 1000
7 Electronics Dana 750

クエリ:

SELECT seller_name, product_category, revenue,
       DENSE_RANK() OVER (PARTITION BY product_category ORDER BY revenue DESC) AS dense_rank
FROM sales;

結果:

seller_name product_category revenue dense_rank
Alice Electronics 1000 1
Alice Electronics 1000 1
Bob Electronics 850 2
Dana Electronics 750 3

使い方例:行のナンバリング

タスク:orders テーブルの全注文を日付順に番号を振る。

SELECT order_id, customer_name, order_date,
       ROW_NUMBER() OVER (ORDER BY order_date) AS order_number
FROM orders;

結果:注文リストが、実行順に番号付きで出てくる。

使い方例:各カテゴリのトップ3セラー

タスク:各商品カテゴリでトップ3のセラーを決める。

WITH ranked_sales AS (
    SELECT seller_name, product_category, revenue,
           RANK() OVER (PARTITION BY product_category ORDER BY revenue DESC) AS rank
    FROM sales
)
SELECT seller_name, product_category, revenue
FROM ranked_sales
WHERE rank <= 3;

使い方例:同じ成績の検出

タスク:各カテゴリで同じ売上のセラーがいるかどうか調べる。

SELECT seller_name, product_category, revenue,
       DENSE_RANK() OVER (PARTITION BY product_category ORDER BY revenue DESC) AS dense_rank
FROM sales;

これで、同じ値で「くっついてる」ランクが見えるようになるよ。

2
タスク
SQL SELF, レベル 59, レッスン 1
ロック未解除
ROW_NUMBER()関数を使った行番号の付与
ROW_NUMBER()関数を使った行番号の付与
コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION