0
0

More than 3 years have passed since last update.

🍰【CakePHP2】任意のカラムでGROUP BYした最新レコードの取得

Last updated at Posted at 2019-12-02

環境

PHP 7.2.21
CakePHP 2.10.18
MySQL 5.7.27

内容

CakePHP2のfind()では特定のカラムでGROUP BYした上でそれぞれの最新レコード取得するのが難しかったので後の為にメモ

やりたいこと

下記のようなテーブルでpage_idをGROUP BYしてそのページごとの最新レコードが欲しい
あと、できればpaginatorされてほしい

test_page_history.sql
CREATE TABLE `test_page_history` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `page_id` varchar(50) NOT NULL,
  `update_date` datetime NOT NULL,
  `updater_name` varchar(50) NOT NULL,
  `reason` varchar(50) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `test_UN` (`page_id`,`update_date`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4

① 元データ

"id" "page_id" "update_date" "updater_name" "reason"
1 A-1 "2019-12-01 00:00:00.0" alice ページ新規追加
2 A-2 "2019-12-02 00:00:00.0" bob ページ新規追加
3 A-1 "2019-12-05 00:00:00.0" charlie 機能追加
4 A-3 "2019-12-05 00:00:00.0" alice 新規追加
5 A-1 "2019-12-06 00:00:00.0" delta 不要の為ページ削除
6 A-3 "2019-12-07 00:00:00.0" charlie デザイン修正

② 取得したいテータ(page_idでまとめた最新レコード)

"id" "page_id" "update_date" "updater_name" "reason"
5 A-1 "2019-12-06 00:00:00.0" delta 不要の為ページ削除
2 A-2 "2019-12-02 00:00:00.0" bob ページ新規追加
6 A-3 "2019-12-07 00:00:00.0" charlie デザイン修正

やったこと

Modelにカスタムfinderを追加実装し
conditionsで力業を使った

TestPageHistory.php
<?php

App::uses('AppModel', 'Model');

class TestPageHistory extends AppModel {
    public $useTable    = 'test_page_history';
    public $primaryKey  = 'id';
    public $useDbConfig = 'admin';

    // 自作するカスタムfinderを使用可能に設定
    public $findMethods = [
        'newest' => true,
    ];

    /**
     * newest実装
     *
     * @param string $state
     * @param array  $query
     * @param array  $results
     */
    protected function _findNewest($state, $query, $results = []) {
        if ($state === 'before') {
            $query['conditions']["{$this->alias}.update_date = (SELECT MAX(b.update_date) FROM test_page_history AS b WHERE TestPageHistory.page_id = b.page_id)"] = [true];
            $query['order']["{$this->alias}.page_id"] = ['asc'];
            return $query;
        }

        return $results;
    }
}

Controllerはカスタムfinderを使うのみ

TestController.php
<?php

App::uses('AppController', 'Controller');
App::uses('TestPageHistory', 'Model');

class PointsListController extends AppController {

    public $uses = [
        'TestPageHistory',
    ];

    /**
     * 一覧
     *
     * @return void
     */
    public function index(): void {
        // カスタムfinderである「'newest'」でデータ取得
        $test = $this->TestPageHistory->find('newest');
        var_dump($test);
      }

取得結果

page_idごとの最新レコードが取得できている🐈

array(3) {
  [0]=>
  array(1) {
    ["TestPageHistory"]=>
    array(5) {
      ["id"]=>
      string(1) "5"
      ["page_id"]=>
      string(3) "A-1"
      ["update_date"]=>
      string(19) "2019-12-06 00:00:00"
      ["updater_name"]=>
      string(5) "delta"
      ["reason"]=>
      string(27) "不要の為ページ削除"
    }
  }
  [1]=>
  array(1) {
    ["TestPageHistory"]=>
    array(5) {
      ["id"]=>
      string(1) "2"
      ["page_id"]=>
      string(3) "A-2"
      ["update_date"]=>
      string(19) "2019-12-02 00:00:00"
      ["updater_name"]=>
      string(3) "bob"
      ["reason"]=>
      string(21) "ページ新規追加"
    }
  }
  [2]=>
  array(1) {
    ["TestPageHistory"]=>
    array(5) {
      ["id"]=>
      string(1) "6"
      ["page_id"]=>
      string(3) "A-3"
      ["update_date"]=>
      string(19) "2019-12-07 00:00:00"
      ["updater_name"]=>
      string(7) "charlie"
      ["reason"]=>
      string(18) "デザイン修正"
    }
  }
}

paginatorにもつっこめた

TestController.php
            $this->paginate = [
                'conditions' => $conditions,
                'limit'      => $limit,
                'findType'   => 'newest',
            ];
            $this->paginate();
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0