複雑なSQLをEloquentで表現するとき

投稿者: | 2019年4月28日

Laravelの機能の一つにEloquentというORマッパーがあり、これを使ってるとSQLを書くことがほとんどなくなり、Laravelの大きな魅力の一つになっています。

この便利なEloquentですが、複雑なSQLを実現するとなると、ちょっと難しくなります。
例えば下記のようなSQLですと、

select * from users where age >= 20 and age <= 30

Eloquentでは次のように書きます。非常に簡単です。

$users = User::where('age', '>=', 20)->where('age', '<=', 30)->get();

しかし、次のようなSQLになりますと少々厄介です。

select * from users where (age >= 20 and age <= 30) or age >= 60

Eloquentで次のように書くのはもちろん間違いです。

$users = User::where('age', '>=', 20)->where('age', '<=', 30)->orWhere('age', '>=', 60)->get();

この書き方では次のSQLが実行されてしまいます。

select * from users where age >= 20 and age <= 30 or age >= 60

このような括弧を使うようなSQLをEloquentで実現するには、括弧の中のSQLを
無名関数で書くことになります。
つまり先ほどのSQLはこのようになります。

$users = User::where(function($query){
        $query->where('age', '>=', 20)->where('age', '<=', 30);
    })->orWhere('age', '>=', 60)->get();

もう少し複雑な次のようなSQLでしたら、

select * from users where ((age >= 20 and age <= 30) or age >= 60) and height > 175

次のようになります。

$users = User::where(function($query){
        $query->where(function($query){
            $query->where('age', '>=', 20)->where('age', '<=', 30);
        })->orWhere('age', '>=', 60);
    })->where('height', '>', 175)->get();

基本的に括弧の深さだけ無名関数も呼び出していくことになります。
複雑なSQLが必要になった場合は、まずSQLで書いてみて、括弧があればEloquentでは無名関数を使うということを意識してみてください。