環境
PHP 8.1.4RC1
CakePHP 4.3.6
CakePHP4 の ORM で "FROM サブクエリ" を作る
やりたいこと
SELECT base.id
FROM (SELECT h.id FROM hoges h) base
LEFT JOIN moges m ON base.id = m.id
をORMで生成する。
次のコードは最初に書いたもの。
\App\Model\Table\HogeTable
public function getData()
{
// SELECT h.id FROM hoge h をつくる
$this->setAlias('h');
$subquery = $this->find()->select('h.id');
// サブクエリをFROMに指定する
$this->belongsTo('m', [
'className' => 'Moge',
'bindingKey' => ['id'],
'foreignKey' => ['id'],
'joinType' => 'LEFT',
]);
$this->setAlias('base');
$data = $this->find()
->from(['base' => $subquery])
->contain('m')
->select('base.id')
->all();
}
これを実行するとこうなる。
SELECT base.id AS base__id
FROM (SELECT h.id AS h__id FROM hoges base) base
LEFT JOIN moges m ON base.id = m.id
base
にid
というカラムがない(h__id
になっている)
サブクエリの別名もbase
になっている。
問題点
- カラムの別名は未指定だと、ルールに従い自動で付与される。
- クエリを発行しないとテーブルの別名は上書きされる。
どーーしてもサブクエリと違う別名を使いたいのであれば
サブクエリを確定(発行)してしまうか、別のTable
オブジェクトを使う。
$this->setAlias('h');
$subquery = $this->find()->select(['id' => 'h.id'])->sql();
// SQL発行 => SELECT h.id AS id FROM hoges h
ただこれをfrom
に指定すると
SELECT base.id FROM SELECT h.id AS id FROM hoges h LEFT JOIN moge m ON
となる(括弧がつかない)し、結果的に文字列を扱うなら最初から無理にORMでやらなくてもよくない?
対処法
というわけで、解決?策。
\App\Model\Table\HogeTable
public function getData()
{
$sub = clone $this;
$sub->setAlias('h');
$subquery = $sub->find()->select(['id' => 'h.id']);
$this->belongsTo('m', [
'className' => 'Moge',
'bindingKey' => ['id'],
'foreignKey' => ['id'],
'joinType' => 'LEFT',
]);
$this->setAlias('base');
$data = $this->find()
->from(['base' => $subquery])
->contain('m')
->select('base.id')
->all();
}
結果
SELECT base.id AS base__id
FROM (SELECT h.id AS id FROM hoges h) base
LEFT JOIN moges m ON base.id = m.id
余談
調べたらautoAlias(false)
というものを見かけたが、2015年の記事だし、そんなものはなかった。