Eloquent/SQL - 获取查询的行号(排名)
Posted
技术标签:
【中文标题】Eloquent/SQL - 获取查询的行号(排名)【英文标题】:Eloquent/SQL - Get the row number of a query (rank) 【发布时间】:2019-03-26 17:35:32 【问题描述】:我想知道基于我的数据库结构的排名:
我有一个模型 Post
,它属于一个名为 Edition
的模型(也有一个 Edition
有很多 Post
)。
一个Post
有多个Like
。
我想根据特定Edition
中的Like
计数了解Post
的排名。
代码:
// Define the id of an edition
$edition_id = 53;
// The id of the post to retrieve rank
$post_id = 132;
// Compose the query by select all posts, of interested edition ...
$query = App\Models\Post::where('edition_id', $edition_id)
// ... with like count (this produce an additional field named likes_count) ...
->withCount('likes')
// ... in descendig order by this count.
->orderBy('likes_count', 'desc');
// By execute it I can get right results.
$query->get();
对于Laravel Eloquent ORM
不熟悉的人,我报告一下上面代码执行的sql查询:
select `posts`.*, (select count(*) from `likes` where `posts`.`id` = `likes`.`post_id` and `likes`.`deleted_at` is null) as `likes_count`
from `posts`
where `edition_id` = '53' and `posts`.`deleted_at` is null
order by `likes_count` desc
我报告查询结果:
=> Illuminate\Database\Eloquent\Collection #994
all: [
App\Models\Post #993
id: 135,
likes_count: 4,
,
App\Models\Post #1075
id: 134,
likes_count: 3,
,
App\Models\Post #1091
id: 133,
likes_count: 2,
,
App\Models\Post #997
id: 132,
likes_count: 1,
,
App\Models\Post #1038
id: 131,
likes_count: 0,
,
],
如何从组合查询的结果中获取具有某个id
的记录的行位置?
例如,如何检索id = 132
记录的排名结果?
【问题讨论】:
你用的是什么版本的 mysql? @JonasStaudenmeir:在我的开发环境中,我有mysql Ver 14.14 Distrib 5.7.19, for macos10.12 (x86_64) using EditLine wrapper
。
你见过***.com/q/3333665/4848587吗?
@JonasStaudenmeir 感谢您的回复。是的,我已经看过它并且我读到了ROW_NUMBER()
,但我无法以正确的方式实现它。我使用正确的行号进行查询,但如果我按 id 添加过滤器,结果始终为 1,而不是 where id = X
过滤器之前的排名数。
何时检索单个帖子?
【参考方案1】:
您可以使用子查询:
$query = Post::where('edition_id', $edition_id)
->withCount('likes')
->selectRaw('@rank := @rank + 1 rank')
->from(DB::raw('`posts`, (SELECT @rank := 0) vars'))
->orderBy('likes_count', 'desc');
$posts = Post::fromSub($query, 'posts')->paginate();
$post = Post::fromSub($query, 'posts')->find($post_id);
Laravel
Builder::macro('fromSub', function($query, $as)
$this->bindings = array_merge(
array_slice($this->bindings, 0, 1),
['from' => $query->getBindings()],
array_slice($this->bindings, 1)
);
$sql = '('.$query->toSql().') as '.$this->grammar->wrap($as);
return $this->from(DB::raw($sql));
);
【讨论】:
感谢您的回复!我试过了,但我的 Laravel 版本是最后一个 LTS 版本5.5.34
。方法fromRaw
和fromSub
可从版本5.6
获得:还有其他选择吗?如果不是,我会阅读升级指南,但我想继续使用 LTS 版本。
我已替换 fromRaw()
并为 Laravel 5.5 添加了解决方法。您可以使用宏实现fromSub()
。
嗨 Jonas,对不起,我正在计划将 laravel 更新到 5.6,以避免使用您发布的宏解决方案给搜索引擎带来复杂性。没试过,不过明天我会部署当前版本,试试子查询的方法。您知道使用这些查询是否存在任何性能问题?
不,查询应该相当快。
嗨乔纳斯,抱歉迟到了,我很忙。昨天我已将 laravel 更新到 5.6.X 版本,并尝试实施您的解决方案。效果很好!非常感谢您的出色帮助。【参考方案2】:
您可以使用search()方法找到密钥:
搜索方法在集合中搜索给定的值,如果找到则返回其键。如果未找到该项目,则返回 false。
$id = 132;
$key = $query->search(function($post,$id)
return $post->id === $id;
);
【讨论】:
嗨卢卡斯,感谢您的回复!正如您所说,search
方法搜索 collection
。这意味着两件事:1)在我的查询构建器上产生一个Call to undefined method Illuminate\Database\Query\Builder::search()
:要开始工作,我必须执行它并将结果放入带有->get()
method 的集合中。 2)通过执行意味着我必须迭代集合结果中的每个对象:如果我在版本中有成百上千的帖子,它猜测它在时间和内存使用方面的表现会很差。
是的,你是对的,你必须打电话给get
让它工作,可能不会是最优化的事情,但我希望你的情况是我能想到的唯一答案它以任何方式帮助你:)以上是关于Eloquent/SQL - 获取查询的行号(排名)的主要内容,如果未能解决你的问题,请参考以下文章