[CakePHP]モデルのqueryメソッドでfind、findAllと同等の返り値を得る方法

  • warning: date() [function.date]: It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected 'America/Denver' for 'MDT/-6.0/DST' instead in /home/lyniqne/public_html/planetcakephp.org/drupal/sites/all/modules/token/token_node.inc on line 40.
  • warning: date() [function.date]: It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected 'America/Denver' for 'MDT/-6.0/DST' instead in /home/lyniqne/public_html/planetcakephp.org/drupal/sites/all/modules/token/token_node.inc on line 41.
  • warning: date() [function.date]: It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected 'America/Denver' for 'MDT/-6.0/DST' instead in /home/lyniqne/public_html/planetcakephp.org/drupal/sites/all/modules/token/token_node.inc on line 42.
  • warning: date() [function.date]: It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected 'America/Denver' for 'MDT/-6.0/DST' instead in /home/lyniqne/public_html/planetcakephp.org/drupal/sites/all/modules/token/token_node.inc on line 43.
  • warning: date() [function.date]: It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected 'America/Denver' for 'MDT/-6.0/DST' instead in /home/lyniqne/public_html/planetcakephp.org/drupal/sites/all/modules/token/token_node.inc on line 44.
  • warning: date() [function.date]: It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected 'America/Denver' for 'MDT/-6.0/DST' instead in /home/lyniqne/public_html/planetcakephp.org/drupal/sites/all/modules/token/token_node.inc on line 45.
  • warning: date() [function.date]: It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected 'America/Denver' for 'MDT/-6.0/DST' instead in /home/lyniqne/public_html/planetcakephp.org/drupal/sites/all/modules/token/token_node.inc on line 46.
  • warning: date() [function.date]: It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected 'America/Denver' for 'MDT/-6.0/DST' instead in /home/lyniqne/public_html/planetcakephp.org/drupal/sites/all/modules/token/token_node.inc on line 47.
  • warning: date() [function.date]: It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected 'America/Denver' for 'MDT/-6.0/DST' instead in /home/lyniqne/public_html/planetcakephp.org/drupal/sites/all/modules/token/token_node.inc on line 48.
  • warning: date() [function.date]: It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected 'America/Denver' for 'MDT/-6.0/DST' instead in /home/lyniqne/public_html/planetcakephp.org/drupal/sites/all/modules/token/token_node.inc on line 49.
  • warning: date() [function.date]: It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected 'America/Denver' for 'MDT/-6.0/DST' instead in /home/lyniqne/public_html/planetcakephp.org/drupal/sites/all/modules/token/token_node.inc on line 50.
  • warning: date() [function.date]: It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected 'America/Denver' for 'MDT/-6.0/DST' instead in /home/lyniqne/public_html/planetcakephp.org/drupal/sites/all/modules/token/token_node.inc on line 51.
  • warning: date() [function.date]: It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected 'America/Denver' for 'MDT/-6.0/DST' instead in /home/lyniqne/public_html/planetcakephp.org/drupal/sites/all/modules/token/token_node.inc on line 56.
  • warning: date() [function.date]: It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected 'America/Denver' for 'MDT/-6.0/DST' instead in /home/lyniqne/public_html/planetcakephp.org/drupal/sites/all/modules/token/token_node.inc on line 57.
  • warning: date() [function.date]: It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected 'America/Denver' for 'MDT/-6.0/DST' instead in /home/lyniqne/public_html/planetcakephp.org/drupal/sites/all/modules/token/token_node.inc on line 58.
  • warning: date() [function.date]: It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected 'America/Denver' for 'MDT/-6.0/DST' instead in /home/lyniqne/public_html/planetcakephp.org/drupal/sites/all/modules/token/token_node.inc on line 59.
  • warning: date() [function.date]: It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected 'America/Denver' for 'MDT/-6.0/DST' instead in /home/lyniqne/public_html/planetcakephp.org/drupal/sites/all/modules/token/token_node.inc on line 60.
  • warning: date() [function.date]: It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected 'America/Denver' for 'MDT/-6.0/DST' instead in /home/lyniqne/public_html/planetcakephp.org/drupal/sites/all/modules/token/token_node.inc on line 61.
  • warning: date() [function.date]: It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected 'America/Denver' for 'MDT/-6.0/DST' instead in /home/lyniqne/public_html/planetcakephp.org/drupal/sites/all/modules/token/token_node.inc on line 62.
  • warning: date() [function.date]: It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected 'America/Denver' for 'MDT/-6.0/DST' instead in /home/lyniqne/public_html/planetcakephp.org/drupal/sites/all/modules/token/token_node.inc on line 63.
  • warning: date() [function.date]: It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected 'America/Denver' for 'MDT/-6.0/DST' instead in /home/lyniqne/public_html/planetcakephp.org/drupal/sites/all/modules/token/token_node.inc on line 64.
  • warning: date() [function.date]: It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected 'America/Denver' for 'MDT/-6.0/DST' instead in /home/lyniqne/public_html/planetcakephp.org/drupal/sites/all/modules/token/token_node.inc on line 65.
  • warning: date() [function.date]: It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected 'America/Denver' for 'MDT/-6.0/DST' instead in /home/lyniqne/public_html/planetcakephp.org/drupal/sites/all/modules/token/token_node.inc on line 66.
  • warning: date() [function.date]: It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected 'America/Denver' for 'MDT/-6.0/DST' instead in /home/lyniqne/public_html/planetcakephp.org/drupal/sites/all/modules/token/token_node.inc on line 67.

常識かもしれませんが、明言されている記事が見つからなかったのでエントリー。
動作確認バージョンは毎度のBeta 1.2.0.6311です。

queryとfind、findAllでの返り値の違い
例えばfindAllとqueryのそれぞれを使って全件取得した結果の違いを見比べてみます。(DBMSはMySQLを使用)
まずfindAllを使う場合。

$this->User->findAll();

の結果は

Array
(
[0] => Array
(
[User] => Array
(
[id] => 1
[username] => aaa
[password] => xxx
)
)
[1] => Array
(
[User] => Array
(
[id] => 2
[username] => bbb
[password] => yyy
)
)
)

となります。

次にqueryを使った場合。

$this->User->query('select * from users');

の結果は

Array
(
[0] => Array
(
[users] => Array
(
[id] => 1
[username] => aaa
[password] => xxx
)
)
[1] => Array
(
[users] => Array
(
[id] => 2
[username] => bbb
[password] => yyy
)
)
)

となります。
両者の違いは連想配列のkeyが'User'か'users'で異なる部分です。
このままでも使えることは使えますが、使用する側(コントローラやビュー)で配列のkeyが'User'と'users'で混在するのはシステムで統一感が無く、少し気持ち悪いです。
そこで次の方法を使えば、queryメソッドの場合も配列のkeyを'User'にすることが出来ます。

findAllと同じ返り値を得る方法
以下のようにテーブルに別名を付ける、その別名が配列のkeyとなります。

$this->User->query('select * from users as User');

とすると、

Array
(
[0] => Array
(
[User] => Array
(
[id] => 1
[username] => aaa
[password] => xxx
)
)
[1] => Array
(
[User] => Array
(
[id] => 2
[username] => bbb
[password] => yyy
)
)
)

の結果が返ってきます。

デバッグモードで表示されるSQLクエリを見ながら色々試してみた結果、この方法を見つけました。

結合させても大丈夫
結合させるテーブルにも別名をつけておくとアソシエーションを使った場合と同等の返り値を得ることが出来ます。

$this->User->query('select * from users as User left join posts as Post on Post.user_id = User.id');

の結果は

Array
(
[0] => Array
(
[User] => Array
(
[id] => 1
[username] => aaa
[password] => xxx
)
[Post] => Array
(
[id] => 1
[user_id] => 1
[title] => title1
[body] => hogehoge
)
)
[1] => Array
(
[User] => Array
(
[id] => 2
[username] => bbb
[password] => yyy
)
[Post] => Array
(
[id] => 2
[user_id] => 2
[title] => title2
[body] => hogehoge
)
)
)

となります。

ちなみにPostgreSQLでは
少し試した感じではMySQLほど簡単には出来ないようでした。
PostgreSQLでqueryメソッドを使った場合、

$this->User->query('select * from users');

の結果は

Array
(
[0] => Array
(
[0] => Array
(
[id] => 1
[username] => aaa
[password] => xxx
)
)
[1] => Array
(
[0] => Array
(
[id] => 2
[username] => bbb
[password] => yyy
)
)
)

と配列のkeyに'users'すら入りません。

次にMySQLではうまくいったテーブル名の別名をつけて、

$this->User->query('select * from users as "User"');

としても結果は変わらず。

色々試した結果、

$this->User->query('select id as "User__id", username as "User__username", password as "User__password" FROM users')

という風にフィールド名の別名として

keyにしたい文字 + __(アンダーバー2つ) + 列名

をセットすると、

Array
(
[0] => Array
(
[User] => Array
(
[id] => 1
[username] => aaa
[password] => xxx
)
)
[1] => Array
(
[User] => Array
(
[id] => 2
[username] => bbb
[password] => yyy
)
)
)

という期待する値が返ってきました。

取得したいフィールド全てに別名を付けていかないと駄目なようです。

使いどころ
queryメソッド自体、あまり出番が少ないかもしれませんが、

    • 複雑なSQLの組み立てが必要なためにqueryメソッドを使う場合
    • SQLチューニングによるパフォーマンス改善のためにfind系メソッドからqueryメソッドに置き換える場合

などの際にこの方法を知っておくと、コントローラーやビューで返り値を今までどおり扱えて便利かも知れません。