Skip to content

グループごとに上位N行を選択する snippet

すべてのグループの内側で上位N行を残します。部門ごとの給与上位3人、顧客ごとの最新注文といった形です。GROUP BY は各グループを1行に潰しますが、ここではそれこそが間違いです。代わりにランクを付けます。ROW_NUMBER() OVER (PARTITION BY グループ ORDER BY 順位) はグループ内の行に番号を付けるので、そのランクでフィルタすればグループごとにちょうどN行が残ります。同点の行を両方残したい場合は ROW_NUMBER() を RANK() に差し替えてください。

すべてのグループの内側で上位N行を残します。部門ごとの給与上位3人、顧客ごとの最新注文といった形です。GROUP BY は各グループを1行に潰しますが、ここではそれこそが間違いです。代わりにランクを付けます。ROW_NUMBER() OVER (PARTITION BY グループ ORDER BY 順位) はグループ内の行に番号を付けるので、そのランクでフィルタすればグループごとにちょうどN行が残ります。同点の行を両方残したい場合は ROW_NUMBER() を RANK() に差し替えてください。

Runnable recipe · 1 languages
Files & Datasqlwindow-functionsgrouping

Every language

1 languages, copy-ready. One at a time with syntax highlighting, or all inline.

SQLSQLrunnable
-- Top 3 earners per department: rank inside each group, keep rn <= 3.
WITH ranked AS (
  SELECT
    department,
    name,
    salary,
    ROW_NUMBER() OVER (PARTITION BY department ORDER BY salary DESC) AS rn
  FROM employees
)
SELECT department, name, salary
FROM ranked
WHERE rn <= 3
ORDER BY department, salary DESC;

Runs as-is in the playground's SQLite (window functions need SQLite 3.25+). RANK() keeps ties — two rows share rank 1 and both survive an rn <= N filter — while ROW_NUMBER() always breaks ties arbitrarily.

Run in the SQL playground →

Keep going

Read the sql-window-functions cheatsheet →