如何让 sql 排名查询工作以查找特定 id 的排名

Posted

技术标签:

【中文标题】如何让 sql 排名查询工作以查找特定 id 的排名【英文标题】:how to get a sql rank query working to find the rank of a specific id 【发布时间】:2021-06-08 11:55:34 【问题描述】:

我尝试进行排名查询,但无法使其正常工作。排名是按照最高的market_cap后跟最高的id来计算的,如果market_cap的值相同,则条件active必须为1。我只想要最后一个特定id的排名。

表:

id market_cap active expected rank
1 67000 1 4
2 197000 1 1
3 67000 1 3
4 127000 1 2
5 17000 1 5
6 37000 1 5
7 2237000 0 /

这是 php(Laravel) 代码,它完全可以做到这一点并且正在工作,但我想将它用作普通 SQL 来提高速度,因为我的表有 20k 行。

    $token_list = DB::table('tokens')->where('active', 1)->orderBy('market_cap', 'desc')->orderBy('id', 'desc')->get(array('id'));
    foreach($token_list as $key => $token)
        if($token->id == $data['token']->id)
            $token_rank = $key+1;
        
    

当前查询尚未工作(它停止对所有 market_cap 为 0 的结果工作,即数千个,它们都获得相同的排名,即最后一个排名数字):

    $rank_query = DB::select("SELECT FIND_IN_SET(market_cap, ( SELECT GROUP_CONCAT(market_cap ORDER BY market_cap DESC, id DESC) FROM tokens WHERE active = 1)) AS rank FROM tokens WHERE id = $data['token']->id");
    $token_rank = $rank_query[0]->rank;

【问题讨论】:

你不会在 Laravel 和 SQL 中做同样的事情。所以无论你在做什么,都没有可比性。 @shaedrich 就是这样。我想在 SQL 中获得与我的 PHP 中相同的结果。结果已经几乎相同,只是 market_cap 0 结果排名相同。具有market_cap 的所有内容都与我的php 代码排名相同。 可能存在误解:您的原始查询是在模仿 Laravel 查询,但并不等同。您在原始 sql 中所做的事情仍然可以拆分为查询构建器语句。所以你的问题似乎不合理。 【参考方案1】:

在 SQL 查询中,可以使用row_number():

select t.*
from (select t.*,
             (case when active
                   then row_number() over (partition by active order by market_cap desc, id desc)
              end) as ranking
      from t
     ) t
where . . . 

您可以将过滤条件放在外部查询中。

【讨论】:

就是这样!我以前尝试过这种语法,但我一定做错了什么。这很有效,非常感谢,将解读该查询的确切含义,因为它看起来仍然让我有些困惑。 对于 mysql 5.7(在我的实时服务器上使用),MySQL 似乎不支持 ROW_NUMBER() OVER、RANK() 等“分析函数”。支持从mysql 8开始,mysql 5.7还有其他方法吗?【参考方案2】:

你也可以用 Laravel 的查询构建器来做这样的事情。无需使用原始 sql。

$marketCapQuery = DB::table('tokens')->selectRaw('GROUP_CONCAT(market_cap ORDER BY market_cap DESC, id DESC)'->where('active', 1)->toSql();
$rank_query = DB::table('tokens')->selectRaw("FIND_IN_SET(market_cap, ( '.$marketCapQuery.') AS rank'->where('id', $data['token']->id);
$token_rank = $rank_query[0]->rank;

【讨论】:

以上是关于如何让 sql 排名查询工作以查找特定 id 的排名的主要内容,如果未能解决你的问题,请参考以下文章

高效查询 - 查询表 A 中的特定 ID 组时,如何检查表 B 中的条件以查找表 A 中的选定 ID?

如何查询我的所有视图设计以查找 SQL Server 中的特定字符串?

sql - 有没有办法过滤SELECT查询的结果,使用另一个SELECT查询?

如何强制 SQL Server 以特定顺序执行查询

如何改进此 LINQ 查询以查找用户将列表中的所有技能

我如何找到特定列的排名位置