CakePHPでgroup by構文を使う
CakePHPのmodelでgroup by使おうとしたのだけども、findAllじゃどうやらできないらしいのでソースをちらほら読んでたら機能はあるみたいなので試してみた(そりゃあるよな
Cakeのバージョンはcake_1.2.0.7692-rc3でございます。ちょっと古いな。
とりあえず↑にも書いたけど、findAllでやると無理っぽい。ので、findでfindAllのように実装すると細かいところまで設定できるようになってる。
cake/libs/model/model.php
Line.1767~
function find($conditions = null, $fields = array(), $order = null, $recursive = null) { if (!is_string($conditions) || (is_string($conditions) && !array_key_exists($conditions, $this->_findMethods))) { $type = 'first'; $query = array_merge(compact('conditions', 'fields', 'order', 'recursive'), array('limit' => 1)); } else { list($type, $query) = array($conditions, $fields); } $db =& ConnectionManager::getDataSource($this->useDbConfig); $this->findQueryType = $type; $this->id = $this->getID(); $query = array_merge( array( 'conditions' => null, 'fields' => null, 'joins' => array(), 'limit' => null, 'offset' => null, 'order' => null, 'page' => null, 'group' => null, 'callbacks' => true ), (array)$query );
としていて、$fieldsをarray_mergeしているのがわかる。で、findAllはっつーと
function findAll($conditions = null, $fields = null, $order = null, $limit = null, $page = 1, $recursive = null) { //trigger_error(__('(Model::findAll) Deprecated, use Model::find("all")', true), E_USER_WARNING); return $this->find('all', compact('conditions', 'fields', 'order', 'limit', 'page', 'recursive')); }
としていて、findでallをしてやると全部検索になるっていう。
まぁ今回findAll使わないけど、こんな感じになってるよっていう感じで。
今回のデータ。
create table groups ( id INT(11) unsigned NOT NULL auto_increment, sex enum("male","female") NOT NULL default "male", age int(11) unsigned NOT NULL default 0, modified datetime, created datetime, PRIMARY KEY (id) ); insert into groups (sex, age) values ("male",10), ("female",10), ("female",30), ("female",20), ("male",30), ("male",20), ("female",20), ("male",20), ("female",10), ("male",10); mysql> select * from groups; +----+--------+-----+----------+---------+ | id | sex | age | modified | created | +----+--------+-----+----------+---------+ | 1 | male | 10 | NULL | NULL | | 2 | female | 10 | NULL | NULL | | 3 | female | 30 | NULL | NULL | | 4 | female | 20 | NULL | NULL | | 5 | male | 30 | NULL | NULL | | 6 | male | 20 | NULL | NULL | | 7 | female | 20 | NULL | NULL | | 8 | male | 20 | NULL | NULL | | 9 | female | 10 | NULL | NULL | | 10 | male | 10 | NULL | NULL | +----+--------+-----+----------+---------+ 10 rows in set (0.00 sec)
mysql> SELECT age, count(age) as cnt FROM groups GROUP BY age ORDER BY cnt DESC LIMIT 3 ; +-----+-----+ | age | cnt | +-----+-----+ | 10 | 4 | | 20 | 4 | | 30 | 2 | +-----+-----+ 3 rows in set (0.00 sec)
適当に。↑のクエリを発行したいとします。
先ほどのプログラムも見たとおりだけど、array_mergeの中に、groupというのがあるので、これに値を渡せばよいことがわかります。
ってことで、こんな感じにfindのfiledsにあたる部分の配列を作成します。
$fields = array( "conditions" => array(), "fields" => "age, count(Group.age) as cnt", "limit" => 3, "group" => "age", "order" => "ORDER BY cnt DESC", ); $result = $this->Group->find("all", $fields);
まー見ればわかると思うけど、filedsの中身は、array_mergeでマージされるようにパラメータをうまく調整しただけです。
ちなみに単品テーブルで、アソシエーションはなしです。
これの結果が以下。
Array
(
[0] => Array
(
[Group] => Array([age] => 10)
[0] => Array([cnt] => 4)
)
[1] => Array
(
[Group] => Array([age] => 20)
[0] => Array([cnt] => 4)
)
[2] => Array
(
[Group] => Array([age] => 30)
[0] => Array([cnt] => 2)
)
)こんな感じ。
知らなかったのですが、モデル名にあたる部分(この場合だとage)はGroupの配列はいってくるけど、それ以外は素の配列で戻ってくるのね。ちょっと手間だな。
「count(Group.age) as cnt」の部分を「count(Group.age) as Group.cnt」っていうこともしてみたけど、SQLエラーになった\(^o^)/そりゃそうだけどって感じだけども。
実践で使うなら、modelに書いてデータを整理しなおしてから返したほうがよさそうね。
Categories: cakephpTags: cakephp
good site!
コメント by car insurance — 2009 年 2 月 7 日 @ 6:33 PM