Loading
  • LIGHT

  • DARK

ROUTE

ルートゼロの
アクティビティ

【図解・実践コード付き】MySQLのROW_NUMBER()完全ガイド|最新データを1件だけ抽出するROW_NUMBER()の使い方順番付けの基本と実務での活用法

2

はじめに:データに「順番」をつけたいとき、どうしていますか?

  • 「最新の投稿に番号を振りたい」

  • 「同じカテゴリごとに1位・2位・3位とランキングしたい」

  • 「複数条件で最初のデータだけを抽出したい」

こんな課題、あなたも感じたことありませんか?

MySQLでは、ROW_NUMBER()関数を使えば、データに「順番(連番)」を付けることができます。これは、データ分析・画面表示・業務帳票など、あらゆる実務で非常に役立つ機能です。

本記事では、ROW_NUMBER()の基本から応用までをわかりやすく、かつ実務的に解説します。


ROW_NUMBER()とは?|SQLウィンドウ関数の基本

ROW_NUMBER()の役割

ROW_NUMBER()は、データの並び順に応じて、連番(1, 2, 3…)を付けるウィンドウ関数です。

ROW_NUMBER() OVER (ORDER BY column_name)
  • OVER句内で指定したORDER BYの順序に従って番号が振られます。

  • 結果はサブクエリやCTE(共通テーブル式)と一緒に使うことが多いです。


▼ 基本構文と実行例

以下は、ユーザーのログイン履歴に順番を付ける例です。

SELECT
  user_id,
  login_date,
  ROW_NUMBER() OVER (ORDER BY login_date DESC) AS login_rank
FROM user_logins;
+---------+---------------------+-------------+
| user_id | login_date          | login_rank  |
+---------+---------------------+-------------+
| 101     | 2024-12-15 10:00:00 | 1           |
| 101     | 2024-12-14 08:30:00 | 2           |
| 102     | 2024-12-13 09:15:00 | 3           |
+---------+---------------------+-------------+

最新のログインから順に1位・2位…と並ぶようになります。


グループごとに順位をつけるには?|PARTITION BYの活用

目的別に順位をつける

例えば、「ユーザーごとのログイン回数を1位から数えたい」というケースでは、PARTITION BY句を使います。

SELECT
  user_id,
  login_date,
  ROW_NUMBER() OVER (
    PARTITION BY user_id
    ORDER BY login_date DESC
  ) AS user_rank
FROM user_logins;

図解テキスト

ROW_NUMBERのイメージ】

[user_idでグループ化]
  ↓
[login_dateでソート]
  ↓
[各グループ内で1〜Nを付与]

サブクエリで「最新1件だけ」を取り出す

ROW_NUMBER()をサブクエリと組み合わせると、「グループごとに最新の1件だけ抽出する」ことも可能です。

SELECT *
FROM (
  SELECT
    user_id,
    login_date,
    ROW_NUMBER() OVER (
      PARTITION BY user_id
      ORDER BY login_date DESC
    ) AS rn
  FROM user_logins
) AS ranked
WHERE rn = 1;

→ ユーザーごとに最新ログイン1件を取得できます。


よくあるつまずき|ROW_NUMBER()の落とし穴と解決法

 間違った実装例:GROUP BYとの併用で意図しない結果に

SELECT
  user_id,
  MAX(login_date),
  ROW_NUMBER() OVER (ORDER BY login_date DESC)
FROM user_logins
GROUP BY user_id;
  • ROW_NUMBER()とGROUP BYを同時に使うと不整合になりがちです。

  • グループ化した時点で、ROW_NUMBERの前提(行単位での並び)が崩れます。


正しい実装:サブクエリやCTEで分離

WITH ranked_logins AS (
  SELECT
    user_id,
    login_date,
    ROW_NUMBER() OVER (
      PARTITION BY user_id
      ORDER BY login_date DESC
    ) AS rn
  FROM user_logins
)
SELECT * FROM ranked_logins WHERE rn = 1;

ロジックを明確に分けることで、意図通りのデータが得られます。


まとめ:ROW_NUMBER()を使いこなすために

記事のポイント再確認

  • ROW_NUMBER():並び順に応じて連番を振るウィンドウ関数

  • PARTITION BY:グループごとの連番を付ける

  • ORDER BY:並び順の基準を定める

  • サブクエリ / CTE:抽出条件と組み合わせる際の定番テクニック

ROW_NUMBER()を用いた実行環境を使いたい方は

  • ローカルのMySQL環境(8.0以降)

  • オンラインSQL実行サービス

  • Dockerで簡単構築できるMySQLイメージ

などで試してみてください。

【外部リンク】

MySQL 公式ドキュメント: Window Functions

SQL Tutorial: ROW_NUMBER() 関数の使い方

Microsoft Docs: ROW_NUMBER 関数

【内部リンク】

初心者向けSQL講座|SELECT文の書き方と実行順を完全解説

【SQL】副問い合わせ入門|基本構文から実例まで徹底解説

【Docker入門】MySQL環境を手軽に構築する方法を徹底解説

RANKINGranking-icon

LATEST POSTS

もっとルートゼロを知りたいなら

DISCOVER MORE