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