查找每个位置的前 3 名用户

Posted

技术标签:

【中文标题】查找每个位置的前 3 名用户【英文标题】:Find top 3 users per location 【发布时间】:2013-04-06 09:24:50 【问题描述】:

我对 SQL 相当陌生,正在解决一些实践问题。我有一个示例 Twitter 数据库,我正在尝试根据关注者数量找到每个位置的前 3 名用户。

这是我正在使用的表格:

id_follower_location

        id       | followers | location 
-----------------+-----------+----------
 id28929238      |         1 | Toronto
 id289292338     |         1 | California
 id2892923838    |         2 | Rome
 .
 .

locations

           location       
----------------------
 Bay Area, California
 London
 Nashville, TN
.
.

我已经能够通过以下方式找到“***”用户:

create view top1id as 
  select location, 
    (select id_followers_location.id from id_followers_location 
      where id_followers_location.location = locations.location 
      order by followers desc limit 1
    ) as id 
  from locations;

create view top1 as 
  select location, id, 
    (select followers from id_followers_location 
      where id_followers_location.id = top1id.id
    ) as followers 
  from top1id;

我能够想出解决这个问题的唯一方法是找出“Top 1st”、“Top 2nd”、“Top 3rd”,然后使用union 将它们组合起来。这是正确/唯一的方法吗?还是有更好的办法?

【问题讨论】:

一个用户可以拥有多个位置吗? @FoolishSeth 对 postgres 是,对用户没有多个位置。谢谢 像大多数此类问题一样,您忘了提及如何处理关系?当 5 个人分享相同数量的关注者时,您想返回什么?您希望每个位置恰好三行吗?如何决定?随机的?随意的?其他标准? 【参考方案1】:

前 n

使用rank(),您将获得至少 3 行(如果更少,则更少)。如果前 3 个排名之间存在平局,则可能会返回更多行。见:

PostgreSQL equivalent for TOP n WITH TIES: LIMIT "with ties"?

如果您希望每个位置正好 3 行(如果存在的话,则更少),您必须打破平局。一种方法是使用row_number() 而不是rank()

SELECT *
FROM (
   SELECT id, location
        , row_number() OVER (PARTITION BY location ORDER BY followers DESC) AS rn
   FROM   id_follower_location
   ) r
WHERE  rn <= 3
ORDER  BY location, rn;

您可能希望将ORDER BY 添加到外部查询以保证排序输出。 如果有超过三个有效的候选人,您会从平局中任意选择 - 除非您在 OVER 子句中添加更多 ORDER BY 项目以打破平局。

前 1 名

至于您获取 top 1 行的查询:在 PostgreSQL 中有一个 much 更简单、更快的方法:

SELECT DISTINCT ON (location)
       id, location           -- add additional columns freely
FROM   id_follower_location
ORDER  BY location, followers DESC;

此密切相关的答案中有关此查询技术的详细信息:

Select first row in each GROUP BY group?

【讨论】:

【参考方案2】:

您可以使用窗口函数来做到这一点:http://www.postgresql.org/docs/9.1/static/tutorial-window.html

例如(未测试可能需要稍微修正语法):

SELECT follower_ranks.id, follower_ranks.location 
FROM (
    SELECT id, location, 
      RANK() OVER (PARTITION BY location ORDER BY followers DESC) 
    FROM id_follower_location
) follower_ranks 
WHERE follower_ranks.rank <= 3;

【讨论】:

以上是关于查找每个位置的前 3 名用户的主要内容,如果未能解决你的问题,请参考以下文章

在 MySQL 表中查找每个用户的最新位置

noip模拟赛3确定的位置 (map的遍历 位置原理)

查找旅行距离最长的前 100 名用户及其姓名

老男孩教育每日一题-2017年3月21日:查找占用内存的前3名进程

查找id在每个位置花费的时间

soldiers