查找每个位置的前 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 个排名之间存在平局,则可能会返回更多行。见:
如果您希望每个位置正好 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 名用户的主要内容,如果未能解决你的问题,请参考以下文章