Laravel 5.8 クエリビルダーでWhere句付きのサブクエリ

Laravel

LaravelのクエリビルダーでサブクエリにWhere句があったときにいろいろと調べましたのでまとめます。

Where句のバインド値をマージしないとエラーになる

わざわざサブクエリにする必要はありませんが、確認のため以下のSQLで試してみたいと思います。

select * from (
    select * from table1 where status = 'Success'
) as s1
left join (
    select * from table2 where status = 'New'
) as s2 on s1.id = s2.relid
where t.id = 1

先にサブクエリを定義して、DB::raw()を使用してSQLを組み立てて行きます。
以下のコードで問題はないと思っていましたが、バインド値がないためエラーになってしまいました。

        $subquery1 = \DB::table('table1')
            ->where('status', '=', 'Success');
        $subquery2 = \DB::table('table2')
            ->where('status', '=', 'New');
        $query = \DB::table(\DB::raw("({$subquery1->toSql()}) as s1"))
            ->leftjoin(\DB::raw("({$subquery2->toSql()}) as s2"), function($join){
                $join->on('s1.id', '=','s2.relid');
            })
        ->where('t.id', '=', 1);
        $data = $query->get();

実際にmergeBindings()を使ってバインド値をマージします。
マージする順番も気をつける必要がありますので注意してください。

SQLの上から順番になるようにマージしていきます。

        $subquery1 = \DB::table('table1')
            ->where('status', '=', 'Success');
        $subquery2 = \DB::table('table2')
            ->where('status', '=', 'New');
        $query = \DB::table(\DB::raw("({$subquery1->toSql()}) as s1"))
            ->leftjoin(\DB::raw("({$subquery2->toSql()}) as s2"), function($join){
                $join->on('s1.id', '=','s2.relid');
            })
            ->mergeBindings($subquery1)
            ->mergeBindings($subquery2)
        ->where('t.id', '=', 1);
        $data = $query->get();

バインド値はgetBindings()で確認することができます。

    $query->getBindings()

コメント