ROW_NUMBERで「グループごとに最新1件」

ROW_NUMBERで「グループごとに最新1件」を安定して取る(同率・タイブレークまで)

この記事で分かること

  • 「ユーザーごとの最新注文」「端末ごとの最新ログ」など、実務で頻出の"最新1件"を安定して書ける
  • ROW_NUMBER() のテンプレをそのまま使える
  • 同率や同時刻でも結果が揺れないように、タイブレークを入れられる

結論:最新1件は ROW_NUMBER + タイブレーク

LIMIT 1 だけでは「最新」が定義できません。「何を最新とするか」を ORDER BY
に書き、同時刻などの揺れをIDで止めるのが基本です。

最小テンプレ(まずこれだけ覚える)

SELECT *
FROM (
  SELECT
    t.*,
    ROW_NUMBER() OVER (
      PARTITION BY group_key
      ORDER BY sort_key DESC, tie_breaker DESC
    ) AS rn
  FROM t
) x
WHERE x.rn = 1;

例:ユーザーごとの最新注文を取る

SELECT *
FROM (
  SELECT
    o.*,
    ROW_NUMBER() OVER (
      PARTITION BY o.user_id
      ORDER BY o.ordered_at DESC, o.order_id DESC
    ) AS rn
  FROM orders AS o
) x
WHERE x.rn = 1;

ここが重要(タイブレーク)

  • ordered_at が同時刻の行があり得るなら、必ず order_id などを足して揺れを止めます

よくあるミス

  • ORDER BY が弱くて結果が揺れる(同時刻・同率)
  • JOINした後に ROW_NUMBER() を振って行が増える(1対多の多側を結合している)

練習問題(3問)

  1. ユーザーごとの最新注文を取る(同時刻のタイブレーク込み)
  2. 端末ごとの最新ログを取る(device_id / logged_at / log_id を想定)
  3. 「最新2件」まで取りたい(rn <= 2

次に読む

タイトルとURLをコピーしました