Laravel 5.0 Eloquent关联查询错误:生成SQL不符合预期
问题分析与修复方案
你碰到的问题根源是SQL运算符优先级搞的鬼!你的Eloquent查询里,orWhere没有被包裹在最外层的条件闭包里,导致关联条件users.book_id = books.id只和第一个(a='x' AND b='y')绑定,而和a='xy'的条件变成了OR关系——这就意味着只要书籍表存在任意一条a='xy'的记录,不管它是不是属于当前用户,都会被算进统计里,结果自然就远超预期了。
修正后的Eloquent代码
我们只需要把所有书籍的查询逻辑都包裹在一个顶层的闭包里,让关联条件和整个书籍筛选条件保持AND关系:
$users = \App\User::whereHas('books', function($q) use ($x, $y){ // 用一个外层闭包把所有书籍的筛选条件包起来 $q->where(function ($query) use ($x, $y) { $query->where('a', '=', $x)->where('b', '=', $y) ->orWhere('a', '=', $x.$y); }); });
如果想保留你原来的嵌套闭包写法(虽然没必要,但逻辑是对的),也可以这样写:
$users = \App\User::whereHas('books', function($q) use ($x, $y){ $q->where(function ($query) use ($x, $y) { $query->where(function ($subQuery) use ($x, $y) { $subQuery->where('a', '=', $x)->where('b', '=', $y); })->orWhere(function ($subQuery2) use ($x, $y) { $subQuery2->where('a', '=', $x.$y); }); }); });
修正后的SQL效果
现在生成的SQL会变成这样:
from users where (select count(*) from books where users.book_id = books.id and ((a = ? and b = ?) or (a = ?)) ) >= 1
可以看到,整个书籍的筛选条件((a=x AND b=y) OR a=xy)被包裹在括号里,和关联条件users.book_id = books.id是AND关系——这就保证了只有属于当前用户的书籍满足两个条件之一时,该用户才会被选中。
小提醒
以后在Eloquent里用orWhere的时候一定要留意优先级问题,所有需要作为一组判断的条件,都要记得用where(function(){...})包裹起来,避免出现这种逻辑偏差。
内容的提问来源于stack exchange,提问作者Amarnasan
相关产品推荐
相关产品推荐

