💽

【laravel】順位・ランキングを求める【mysql8系】

2023/04/02に公開

Laravelでクエリを叩き、「順位」を集計したい時の自分のやり方を共有したいと思います。

結論、mysql8系から追加されたウィンドウ関数であるrank()を使う方法がおすすめだと思います。

mamp環境だと、確かmysqlが5系だったので、動かないと思います。

https://dev.mysql.com/doc/refman/8.0/ja/window-function-descriptions.html#function_rank

シチュエーション

ポストの投稿に対して、複数のコメントがされている。
今回、ポストに対するコメント数のランキングを集計するapiが必要になったとする。
バックエンドはlaravelを使っている。
1位、1位の次は3位とする。

※1位、1位の次を2位としたい場合、DENSE_RANK()を使う。

クエリ

SELECT
	posts.id,
	COUNT(*),
	RANK() OVER(
	ORDER by COUNT(*) DESC)
FROM
	posts,
	comments
WHERE
	posts.id = comments.post_id
GROUP BY
	posts.id

結果

Laravelに落とし込む

$rankCollection = DB::table('posts')
    ->select('posts.id',DB::raw('COUNT(*) as comment_sum, RANK() OVER(ORDER BY COUNT(*) DESC) as comment_sum_rank'))
    ->join('comments', 'posts.id', 'comments.post_id')
    ->groupBy('posts.id')
    ->get();

感想

rankを使わなくてもorderbyを使って、コレクションをループさせて、分岐の処理等を加えれば、「1位、1位の次は3位」の要件は満たせますが、
できる限りSQLを使って順位情報を取得できた方が、順位を求めるアルゴリズム、今回の例だとlaravelのコレクションを操作する必要がないので、楽かなと思いました。

Discussion