Php Laravel实现最大n-每组

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'、'='、'

用户表:

会员资格表:

问题 我希望选择具有最新“expire_at”的用户

参考后:, 我尝试了以下方法:

选择 u、 *, m1.* 从…起 用户u u.id上的内部联接成员身份m1=m1.user\u id u.id=m2.user\u id上的左加入成员资格m2 和 m1.到期日 在将m1.*更改为m1.u之后。我得到了我想要的结果

| 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()