5
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Laravel11】SELECT EXISTSの発行にえらい苦労したしなんなら解決していない

Posted at

この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の書き方、どこを探しても何故か全く出てきません。

クエリビルダ

existsdoesntExistメソッドは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を入れる余地がない。

感想

ソースコードリーディングむり。

5
1
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?