このSQLを発行したい。
SELECT hoge.id, EXISTS(SELECT id FROM fuga WHERE fuga.hoge_id = hoge.id AND fuga.status = 1) AS fuga_exists FROM hoge;
このSQLの書き方、どこを探しても何故か全く出てきません。
クエリビルダ
exists
・doesntExist
メソッドはSQLを組み立てるのではなく実行してboolを返してきやがるので今回の用途には役立ちません。
これを書いた時点でSQL全体がSELECT EXISTS
で囲われてしまいます。
whereExists
メソッドは名前のとおりWHERE EXISTS
文を発行するのでSELECT EXISTS
ではありません。
リレーション
こちらの下のほうにひっそりとwithExists
なるメソッドが書かれていました。
しかし例が->withExists('comments')
としか書かれておらず、追加のWHERE句を渡したいときにどうすればいいかとかがさっぱりわかりません。
これは英語版ドキュメントの時点からそうです。
答え
$hoge->withExists(['fuga AS fuga_exists' => function ($query) {
return $query->where('status', '=', 1);
}]);
こんな使い方ドキュメントのどこにも乗ってねえんだけど。
最終的にプルリクにようやくそれっぽい記述を見つけて、ようやくどうにかすることができました。
おまけ
というか本題。
このSQLを発行したい。
SELECT hoge.id, NOT EXISTS(SELECT id FROM fuga WHERE fuga.hoge_id = hoge.id AND fuga.status = 1) AS fuga_not_exists FROM hoge;
こちらの作り方はいまだにわかりません。
JOINにすればいいじゃんとかそういう問題ではないんだよ、このSQLを作りたいんだよ。
ソースコードリーディング
せっかくなのでソースコードを読んでみよう。
QueriesRelationships::withExists()
withAggregate($relation, '*', 'exists')
を呼んでるだけですね。
QueriesRelationships::withAggregate()
やべえ…まったく意味がわからない。
parseWithRelationsで引数を分割して、第二引数がas
ならなんかやってるっぽい。
つまりwithExists('XXX AS fuga_exists')
とか送ればエイリアスを書けそうだ。
下のほう見たらif ($function === 'exists')
とか書かれていた。
中を見るとSQLを直接発行していた。
sprintf('exists(%s) as %s', $query->toSql(), $this->getQuery()->grammar->wrap($alias))
つまり、NOTを入れる余地がない。
感想
ソースコードリーディングむり。