如何使用 Eloquent 对分组结果排序?
Posted
技术标签:
【中文标题】如何使用 Eloquent 对分组结果排序?【英文标题】:How to order grouped results using Eloquent? 【发布时间】:2013-08-12 03:21:19 【问题描述】:我已经尝试解决这个问题一段时间了,但似乎无法让它发挥作用。我有一张与此类似的表。
表格:问题
id yearly_issue year stock created_at updated_at magazine_id
1 10 2000 1 [timestamp] [timestamp] 3
2 12 1994 6 [timestamp] [timestamp] 10
3 36 2007 10 [timestamp] [timestamp] 102
4 6 2002 7 [timestamp] [timestamp] 7
5 6 2002 2 [timestamp] [timestamp] 5
6 12 2003 9 [timestamp] [timestamp] 10
7 11 2003 12 [timestamp] [timestamp] 10
我的问题是我需要对它进行排序(简单!)但是,我只想获取每本杂志中的一本(列杂志 ID)。
到目前为止,我的 Eloquent 查询是:
$issues = Issue::where('stock', ($all ? '>=' : '>'), 0)
->orderBy('year', 'desc')
->orderBy('yearly_issue', 'desc')
->take($perpage)
->get();
我认为添加 groupBy('magazine_id')
会有所帮助,但似乎它只对我有部分帮助。结果的顺序不正确。那么,我的问题是 - 有没有简单的方法解决这个问题?
我一直在尝试对类似问题的各种答案,但我完全无法实现它。
Retrieving the last record in each group
或
How to get the latest record in each group using GROUP BY?
我们将不胜感激。
编辑: 我目前最接近的是:
SELECT i1.*, c.name AS image, m.title AS title
FROM issues i1
INNER JOIN covers c ON i1.id = c.issue_id
INNER JOIN magazines m ON i1.magazine_id = m.id
JOIN (SELECT magazine_id, MAX(year) year, MAX(yearly_issue) yearly_issue FROM issues GROUP BY magazine_id) i2
ON i1.magazine_id = i2.magazine_id
AND i1.year = i2.year
-- AND i1.yearly_issue = i2.yearly_issue
WHERE i1.stock ($all ? '>=' : '>') 0
ORDER BY i1.year DESC, i1.yearly_issue DESC
LIMIT $perpage
但是,它根本没有给我想要的结果。
【问题讨论】:
【参考方案1】:您需要在SELECT
子句中为要按DESC
ending 顺序排列的每一列添加一个MAX
函数。以ASC
ending 顺序排列的列则相反,您需要在SELECT
子句中添加MIN
函数。
您的 Eloquent 查询必须包含 raw 选择:
$issues = DB::table('issues')
->select(DB::raw('id, max(year) as year, max(yearly_issue) as yearly_issue, stock, created_at, updated_at, magazine_id'))
->groupBy('magazine_id')
->orderBy('year', 'desc')
->orderBy('yearly_issue', 'desc')
->take(10)
->get();
唯一的缺点是您需要指定要检索的每一列。并且不要使用*
选择器,它会覆盖select子句中的聚合函数。
更新:似乎在SELECT
子句中添加*
选择器之前 聚合函数也可以。这意味着您将原始选择重写为:
->select(DB::raw('*, max(year) as year, max(yearly_issue) as yearly_issue'))
我认为将 *
选择器放在前面会使聚合函数覆盖它们的列。
【讨论】:
太棒了! =) 这节省了我的周末。 呜呜!那真是救命啊。非常感谢!【参考方案2】:我一直在寻找一种在分组之前对结果进行排序的方法,而这个答案不断出现。就我而言,它是针对用户的消息收件箱的。我需要在用户参与的每个消息线程中显示用户收到的最新消息。我的桌子是这样的:
--------------------------------------------------------------------
| id | sender_id | receiver_id | message | created_at | updated_at |
--------------------------------------------------------------------
| | | | | | |
--------------------------------------------------------------------
这个问题的公认答案对结果进行分组,然后对其进行排序。在对结果进行分组之前,我需要按created_at
字段对结果进行降序排序,以便从每个线程中获取最新消息。无论如何,这是我经过大量挖掘后的最终解决方案:
$sub = $query->orderBy('created_at', 'desc');
return $query->select('*')
->from(DB::raw("($sub->toSql()) as sub"))
->groupBy('sender_id');
这构造了以下查询:
select * from (
select * from `messages`
order by `created_at` desc
) as sub
group by `sender_id`
【讨论】:
非常感谢,它不能满足我的特定需求,->tosql 解析器不能很好地解析参数,但是运行一个简单的原始 sql 查询为我解决了这个问题,添加了我的自己的解决方案:)【参考方案3】:在 mysql 中你可以这样做:
select *
from `UserTable`
where userId=3
group by `field` desc
order by `dateActivityComplete` ;
在 eloquent 中,你会做这样的事情: ->groupBy('field','desc'),然而,在 eloquent 中排序 groupBy 似乎不像 order by 那样是一个选项。
可能是您必须使用原始查询的实例,或者可能是 max 函数。
韦德
【讨论】:
以上是关于如何使用 Eloquent 对分组结果排序?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Laravel 中使用 Eloquent 对 NULL 值进行最后排序