2 回答
TA贡献1770条经验 获得超3个赞
您不能在 Laravel 中选择具有相同名称的两行。第二个将覆盖第一个。请改用别名。
$users = DB::table('users as u')
->select('u.*', 'm1.id as membership_id')
->join('memberships as m1','u.id','=','m1.user_id')
->leftJoin('memberships as m2', function($join){
$join->on('u.id', '=', 'm2.user_id')
->where(function ($query) {
$query->whereColumn('m1.expire_at','<','m2.expire_at')
->orWhere(function ($query) {
$query->whereColumn('m1.expire_at','=','m2.expire_at')
->whereColumn('m1.id','<','m2.id');
});
});
})
->whereNull('m2.id')
->get();
注意:我还在连接中封装了orWhere(),以避免混淆 AND/OR 的顺序。
同样有效的是在选择中使用不同的顺序。例如,您可以使用以下内容:
$query->select([
'm1.*',
'm1.id as membership_id',
'u.*'
])
它将返回两个表的所有列以及新membership_id列。但是如果users表上有一列的名称与表上的列相似memberships,则只users返回表列(例如created_at)。返回列表中最后一个。
TA贡献1829条经验 获得超6个赞
编辑:
正如@Namoshek 所提到的,您不应该选择所有内容,因为您的 SQL 查询中存在重复键问题。我修改了我的答案,使其与@RaymondNijland 的答案相匹配。顺便说一句,即使对于表用户,您也应该准确地选择您需要的内容。不仅针对重复键问题,还针对 SQL 查询的速度。我们考虑得还不够多,但它可以很快对大量结果产生影响。
从数据库发送到 PHP 服务器的数据更少 = 更快
你应该试试这个:
DB::table('users as u')
->select('u.*', 'm1.id as membership_id')
->join('memberships as m1','u.id','=','m1.user_id')
->leftJoin('memberships as m2', function ($join) {
$join->on('u.id', '=', 'm2.user_id')
->on(function($join) {
$join->on('m1.id', '<', 'm2.id')
->on(function($join) {
$join->on('m1.expire_at', '<', 'm2.expire_at')
->orOn('m1.expire_at', '=', 'm2.expire_at');
});
});
})
->whereNull('m2.id')
->toSQL()
如本页 Laravel 文档中所述:https ://laravel.com/api/5.8/Illuminate/Database/Query/JoinClause.html#method_on
您可以将闭包传递给该on()方法,并且orOn()您可以在此闭包中使用该方法。
我测试了它,它给出了与您的 SQL 查询相同的结果。
- 2 回答
- 0 关注
- 172 浏览
添加回答
举报