Php Laravel实现最大n-每组
用户表: 会员资格表: 问题 我希望选择具有最新“expire_at”的用户 参考后:, 我尝试了以下方法: 选择 u、 *, m1.* 从…起 用户u u.id上的内部联接成员身份m1=m1.user\u id u.id=m2.user\u id上的左加入成员资格m2 和 m1.到期日Php Laravel实现最大n-每组,php,mysql,laravel,Php,Mysql,Laravel,用户表: 会员资格表: 问题 我希望选择具有最新“expire_at”的用户 参考后:, 我尝试了以下方法: 选择 u、 *, m1.* 从…起 用户u u.id上的内部联接成员身份m1=m1.user\u id u.id=m2.user\u id上的左加入成员资格m2 和 m1.到期日加入'memberships as m1'、'u.id'、'='、'm1.user_id' ->leftJoin'memberships as m2',函数$join{ $join->on'u.id'、'='、'
| id | name | age | expire_at |
|----|------------|-----|----------------------|
| 1 | Apple | 22 | 2019-08-17T11:19:30Z|
| 2 | Strawberry | 23 | 2019-08-29T11:20:19Z |
| 3 | Orange | 50 | 2019-08-28T11:20:40Z |
在线尝试:
在Lavavel中实现
Laravel框架版本:5.6.39
我正在尝试使用将上述SQL转换为Laravel
$users=DB::表'users as u'
->选择“u.*”、“m1.*”
->加入'memberships as m1'、'u.id'、'='、'm1.user_id'
->leftJoin'memberships as m2',函数$join{
$join->on'u.id'、'='、'm2.user_-id'
->wherefunction$query{
$query->where'm1.expire_at',“您不能在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();
它将返回两个表的所有列以及新的membership\u id列。但是,如果users表中有一列的名称与memberships表中的一列类似,则只返回users表列,例如created\u at。将返回列表中最后一个列。编辑:
正如@Namoshek提到的,您不应该选择所有内容,因为您的SQL查询中存在重复键问题。我修改了我的答案,使其与@RaymondNijland answer匹配。顺便说一句,即使对于表用户,您也应该选择您需要的内容。不仅是重复键问题,而且是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文件所述:
您可以将闭包传递给on方法,在这个闭包中可以使用orOn方法
我对它进行了测试,结果与您的SQL查询结果相同。如果选择only->select'u.*,'m1.expire_at'?很可能这里的问题是,当使用相同的键时,数组元素将被覆盖。每个人都应该知道为什么使用select*通常是个坏主意,特别是在您不知道如何使用de将处理重复的列名称。@RaymondNijland我认为这不是一个Laravel问题。PHP和几乎所有语言一样,在对象和数组上都不能有重复的键,这意味着PDO::FETCH_ASSOC和PDO::FETCH_OBJ以及所有其他语言都不能保存所有请求的列。但是你完全正确,这是一个很好的例子hy SELECT*毕竟不是最好的主意:我知道我在你发表评论之前编辑了评论,但你完全正确这是PHP语言的限制,但因为离开Laraval层,你就无法了解在低级原生PHP上发生的事情,你认为Laraval将在幕后处理此列名的重复。我也发布了这篇文章s关于githiub laravel的问题,有不同的答案。每个人的答案也可以有正确的结果。链接:谢谢你的帮助!!!我这方面的疏忽太不幸了。当然你需要whereColumn。我相应地更新了我的答案。@Namoshek写了一个答案,不是我,我只是评论并删除了关于重复专栏的评论。。
| id | name | age | expire_at |
|----|------------|-----|----------------------|
| 1 | Apple | 22 | 2019-08-17T11:19:30Z|
| 2 | Strawberry | 23 | 2019-08-29T11:20:19Z |
| 3 | Orange | 50 | 2019-08-28T11:20:40Z |
| id | name | age | id | user_id | expire_at |
|----|------------|-----|----|---------|----------------------|
| 1 | Apple | 22 | 2 | 1 | 2019-08-10T11:20:10Z |
| 3 | Orange | 50 | 4 | 3 | 2019-08-02T11:20:30Z |
| 1 | Apple | 22 | 1 | 1 | 2019-08-17T11:19:30Z |
| 2 | Strawberry | 23 | 3 | 2 | 2019-08-29T11:20:19Z |
| 3 | Orange | 50 | 5 | 3 | 2019-08-28T11:20:40Z |
$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();
$query->select([
'm1.*',
'm1.id as membership_id',
'u.*'
])
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()