LaravelでDB::raw使ったWhere句

LaravelのEloquentの機能だけでは実現できないSQLクエリを書きたい場合に、サブクエリを使ったりすると思います。

$sub = Hoge::select(['fuga_id', 'piyo'])
    ->複雑なフィルター();

$subRaw = Str::replaceArray('?', $sub->getBindings(), $sub->toSql());

DB::from("foo, ({$subRaw}) as hoge")
    ->where('foo.fuga_id', 'hoge.fuga_id')
    ->update(['foo.bar' => 3]);

そんなとき、以下のような謎のエラーに遭遇することがあります。

Invalid datetime format: 1292 Truncated incorrect DECIMAL value: 'hoge.fuga_id'

これは where() の2個目の引数にテーブル名カラム名を文字列として使っているのが原因です。Laravelのクエリビルダーは2個目の引数をそのまま値として(’hoge.fuga_id’ という文字列として) foo.fuga_id と比較しようとするので、型が違うので怒られているという感じです。

直すには以下のように DB::raw() を使います。

DB::from("foo, ({$subRaw}) as hoge")
    ->where('foo.fuga_id', DB::raw('hoge.fuga_id'))
    ->update(['foo.bar' => 3]);