シェアありがとうございます!

【Laravel】GROUP BYでグループ化したデータの中から最新レコードを取得する

 こんにちわ、東京は三寒四温ならぬ七寒三温くらいの日々に辟易しているHashiです。今回はLaravelでグループ化したデータの中から各グループの最新レコードのみを取得したいケースに遭遇して、少し手こずったので備忘録も兼ねて紹介したいと思います。

 なお、Laravelとはなんぞやという方は下の記事を参照してください!

環境

 今回の環境は下記の通りとなります。

今回の環境

  • Laravel 5.5
  • MySQL 5.6.37

仕様と要点

 まずは、今回の仕様として下記のようなテーブルがあると仮定します。ちなみに、テーブル名は「status_histories」とします。

ID user_id status
1 1 未申請
2 1 申請中
3 1 承認
4 2 未申請
5 2 申請中
6 3 未申請

 このテーブルには上の表のように「id」,「user_id」,「status」という3つのカラムから構成されているテーブルで、見ての通りユーザーのステータス履歴となっています。

求める結果

 そして、今回このテーブルから欲しい情報は、それぞれのユーザーの最新レーコドということになるので、求める結果は下記の通りとなります。

ID user_id status
3 1 承認
5 2 申請中
6 3 未申請

グループ化したデータから最新レコードを取得する

「GROUP BY」と「ORDER BY」を組み合わせてみる

 さて、各グループの最新レコードは取得していきたいと思いますが、冒頭のとおり少し手こずりました。最初に試したのは下記のコード。

 見ての通り、「GROUP BY」句と「ORDER BY」句を組み合わせた方法です。グループ化してそれぞれの最新レコードが欲しければ、まず単純にグループ化してソートすればいいと思いますよね。でも、この方法だと期待通りの結果は取得できないんですね。うまくいかない理由は処理の順番にあり、「GROUP BY」と「ORDER BY」の組み合わせの場合は、まず「GROUOP BY」が先に処理されるので、ユーザーIDでグループ化された後にソートされたデータが返ってきてしまうからです。

 つまり、上記の方法だと下表のような結果になるということになります。

ID user_id status
6 3 未申請
4 2 未申請
1 1 未申請

 これでは、全然求めるものと違いますね。

「MAX」を使ってみる

 「GROUP BY」と「ORDER BY」の組み合わせではダメということがわかったので、次に試したのが「MAX」を使う方法です。コードはこちらになります。

 この場合、結果がどうなるかというと下表のようになります。

ID user_id status
3 1 未申請
5 2 未申請
6 3 未申請

 「id」に関しては期待通りのidが返ってきますが、「user_id」と「status」に関しては、最新レコードとは違うレコードのものを取得してしまいます。ということでこれもダメですね。

サブクエリを使ってみる

 そして、最後に試したのがサブクエリを使う方法です。上の「MAX」を使う方法だとidに関しては期待通りの結果が得られるので、上記の方法をサブクエリとして使用してみます。今回は下記のように「whereIn」と組み合わせてみました。

 サブクエリで取得したid(各グループの最新レコード)を、whereInを使って取得しています。これでようやく期待通りの結果が得られました。めでたし、めでたし。しかし、もっとスマートな方法はないものか。。

まとめ

 ということで、今回はLaravelでグループ化したデータの中から各グループの最新レコードを取得する方法を紹介しました。もっとスマート方法がありましたら教えてください。

 それでは、今回はここまで!Hashiでした。また!

この記事のまとめ

  • Laravelでグループ化したデータの中から各グループの最新レコードを取得する方法

お仕事のご相談・ご依頼
お気軽にお問い合わせください!

お仕事の依頼はこちら

著者プロフィール

Takanori Hashi

東京、奄美大島、宮崎の3拠点生活を目指すフリーランスのWEBエンジニア兼デザイナー。大人になってもずっと遊んでいたい人。TwitterもInstagramも基本フォローバックするのでお気軽にフォローしてください!

人気記事

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です