Cakephpで普通にINNER JOINするこのエントリをはてなブックマークに追加

12 月 28, 2008

タイトルが微妙すぎて困る!

CakePHPのアソシエーションを使うと、基本LEFTでテーブルをJOINしてfindなどされると思います。
これをINNER JOINにしたい!といっても、hasOneとbelongsToでtype=>”INNER”を指定すればINNER JOINできるのは周知の事実でございますが、hasManyでできねーのかよ!って思って触ってたら案の定できたのでメモ。

まぁSum limitedさんところで書いてある方法にほとんど近いのですが、beforeFindに書くと別のfindでも使ってしまうし、うーんと思ってたんだけど、findAllじゃなくてfindを使えば大丈夫そうなんですよ。

テーブル

mysql> desc users;
+----------+------------------+------+-----+---------+----------------+
| Field    | Type             | Null | Key | Default | Extra          |
+----------+------------------+------+-----+---------+----------------+
| id       | int(11) unsigned | NO   | PRI | NULL    | auto_increment |
| name     | varchar(255)     | NO   |     |         |                |
| modified | datetime         | YES  |     | NULL    |                |
| created  | datetime         | YES  |     | NULL    |                |
+----------+------------------+------+-----+---------+----------------+
4 rows in set (0.00 sec)

mysql> select * from users;
+----+------+---------------------+---------------------+
| id | name | modified            | created             |
+----+------+---------------------+---------------------+
|  1 | a1   | 2008-11-17 08:33:12 | 2008-11-17 08:33:12 |
|  2 | b1   | 2008-11-17 08:33:12 | 2008-11-17 08:33:12 |
+----+------+---------------------+---------------------+
2 rows in set (0.00 sec)

mysql> desc user_comments;
+----------+------------------+------+-----+---------+----------------+
| Field    | Type             | Null | Key | Default | Extra          |
+----------+------------------+------+-----+---------+----------------+
| id       | int(11) unsigned | NO   | PRI | NULL    | auto_increment |
| user_id  | int(11) unsigned | NO   | MUL | 0       |                |
| comment  | varchar(255)     | NO   |     |         |                |
| modified | datetime         | YES  |     | NULL    |                |
| created  | datetime         | YES  |     | NULL    |                |
+----------+------------------+------+-----+---------+----------------+
5 rows in set (0.00 sec)

mysql> select * from user_comments;
+----+---------+---------+---------------------+---------------------+
| id | user_id | comment | modified            | created             |
+----+---------+---------+---------------------+---------------------+
|  1 |       1 | aee     | 2008-11-17 08:34:02 | 2008-11-17 08:34:02 |
|  2 |       1 | addd    | 2008-11-17 08:34:02 | 2008-11-17 08:34:02 |
|  3 |       1 | accdd   | 2008-11-17 08:34:02 | 2008-11-17 08:34:02 |
|  4 |       2 | brree   | 2008-11-17 08:34:02 | 2008-11-17 08:34:02 |
|  5 |       2 | bbawwaa | 2008-11-17 08:34:02 | 2008-11-17 08:34:02 |
|  6 |       2 | bqwedf  | 2008-11-17 08:34:02 | 2008-11-17 08:34:02 |
+----+---------+---------+---------------------+---------------------+
6 rows in set (0.00 sec)

今回使うのは2つ。usersとuser_commentsテーブル。
こいつをuserのモデルでuser_commentsをINNER JOINしてデータをひっぱってくる。

<?php
        $fields = array(
                    "conditions" => array("User.id=1"),
                    "fields" => null,
                    "limit" => 5,
                    "order" => null,
                    "joins" => array(
                                     array("type" => "INNER",
                                           "table" => "`user_comments`",
                                           "alias" => "UserComment",
                                           "conditions" => "`User`.`id`=`UserComment`.`user_id`",
                                          ),
                               ),
                  );
        $result = $this->User->find("all", $fields);
?>

まぁ前回のコードの使いまわしですが気にしない。
fieldsにjoinsがあるので、そこで配列の中に配列でJOINするテーブルを指定すればOK。

まーわかると思うけど
・type → INNER / LEFT
・table → 接続したいテーブル名
・alias → テーブル名のエイリアス。as ~の~にあたる部分。
・conditions → JOINのONにあたる部分を記述。
です。

結果はこちら。

Array
(
    [0] => Array
        (
            [User] => Array
                (
                    [id] => 1
                    [name] => a1
                    [modified] => 2008-11-17 08:33:12
                    [created] => 2008-11-17 08:33:12
                )

        )

    [1] => Array
        (
            [User] => Array
                (
                    [id] => 1
                    [name] => a1
                    [modified] => 2008-11-17 08:33:12
                    [created] => 2008-11-17 08:33:12
                )

        )

    [2] => Array
        (
            [User] => Array
                (
                    [id] => 1
                    [name] => a1
                    [modified] => 2008-11-17 08:33:12
                    [created] => 2008-11-17 08:33:12
                )

        )

)

JOINはできてる!・・・けど、user_commentsがとれてないじゃん!ってことです。
これが注意点ですね。fields(取得するパラメータ)をnullにしてしまうと、JOINの元となるテーブルしかひっぱってこないのです!
ちなみにクエリはこんなの

SELECT `User`.`id`, `User`.`name`, `User`.`modified`, `User`.`created` FROM `users` AS `User` INNER JOIN `user_comments` AS `UserComment` ON (`User`.`id`=`UserComment`.`user_id`) WHERE `User`.`id`=1 LIMIT 5

Userの部分しかひっぱってきてないのがわかりますね。なので、joins使って指定するときはちゃんと「*」なり、「User.*」など、普通のクエリを書くように注意しましょう。

あとちなみに、joinsの中のjoinテーブルを追加すると、多重接続もできるよ!!

<?php
  "joins" => array(
                 array("type" => "INNER",
                       "table" => "`user_comments`",
                       "alias" => "UserComment",
                       "conditions" => "`User`.`id`=`UserComment`.`user_id`",
                 ),
                 array("type" => "INNER",
                       "table" => "`user_skills`",
                       "alias" => "UserSkill",
                       "conditions" => "`User`.`id`=`UserSkill`.`user_id`",
                 ),
            ),
?>

こんな感じってことです。

今年の更新はこれで終わり!
あまり更新できなかったけど、まぁこんなもんかなー!
来年はMySQLクラスターとかで遊びたいな!

それでは皆様よいお年を!

Categories: cakephp
Tags:

コメントはまだありません »

このコメント欄の RSS フィードトラックバック URL

コメントはまだありません。

コメントをどうぞ