Laravel中按玩家去重获取Top Ticket的Eloquent实现咨询
Laravel Eloquent 实现玩家唯一的Top工单查询
方法一:用窗口函数实现(推荐,逻辑清晰)
直接在Eloquent里封装MySQL的ROW_NUMBER()窗口函数,和你原生查询的逻辑一致:
$topTickets = Ticket::select('tickets.*') ->selectSub(function ($query) { $query->selectRaw('ROW_NUMBER() OVER (PARTITION BY player_id ORDER BY score DESC, id ASC) as row_num') ->from('tickets'); }, 'row_num') ->where('row_num', 1) ->orderBy('score', 'DESC') ->orderBy('id', 'ASC') ->get();
PARTITION BY player_id:把工单按玩家分组,每个玩家的工单单独处理ORDER BY score DESC, id ASC:组内先按得分从高到低排,得分相同就选ID更小的- 最后只保留每组的第一条(
row_num=1),再对结果整体按得分、ID排序
方法二:子查询筛选最优工单
如果不想用窗口函数,也可以通过子查询锁定每个玩家的目标工单ID:
$topTickets = Ticket::whereIn('id', function ($query) { $query->selectRaw('MIN(id)') ->from('tickets') ->groupBy('player_id') ->havingRaw('score = (SELECT MAX(score) FROM tickets t2 WHERE t2.player_id = tickets.player_id)'); }) ->orderBy('score', 'DESC') ->orderBy('id', 'ASC') ->get();
- 子查询按玩家分组,先找到每个玩家的最高得分,再取该得分下ID最小的工单
- 主查询通过ID筛选出这些工单,再做整体排序
为什么DISTINCT没用?
distinct是对查询结果的所有字段做去重,没法实现“按玩家分组后保留特定规则记录”的逻辑,所以满足不了你的需求。
内容的提问来源于stack exchange,提问作者Nikola Vi
相关产品推荐
相关产品推荐

