从子查询选取前N条:world表按大洲取前5个国家的SQL实现
解决每个大洲按字母排序取前5个国家的问题
嗨,我懂你现在的困扰——用子查询加LIMIT 1确实能轻松拿到每个大洲的第一个国家,但要扩展到前5个的时候,这种单值匹配的方法就不管用了对吧?
最优解决方案:使用窗口函数ROW_NUMBER()
现代SQL数据库(比如PostgreSQL、MySQL 8.0+、SQL Server等)都支持窗口函数,这是处理这类“分组取Top N”问题的标准方案。我们可以给每个大洲内的国家按字母顺序分配行号,然后筛选出行号≤5的记录就行:
SELECT continent, country FROM ( SELECT continent, country, ROW_NUMBER() OVER (PARTITION BY continent ORDER BY country ASC) AS row_num FROM world ) ranked_countries WHERE row_num <= 5 ORDER BY continent, row_num;
解释下这段代码的逻辑:
- 内层子查询里,
PARTITION BY continent会把数据按大洲分组,ORDER BY country ASC确保每个组内的国家按字母升序排列 ROW_NUMBER()函数给每个组内的每条记录分配一个唯一的行号,从1开始递增- 外层查询只保留行号≤5的记录,也就是每个大洲的前5个国家
兼容老版本数据库的替代方案
如果你的数据库不支持窗口函数(比如MySQL 5.x),可以用关联子查询来实现:
SELECT x.continent, x.country FROM world x WHERE ( SELECT COUNT(*) FROM world y WHERE y.continent = x.continent AND y.country <= x.country ) <= 5 ORDER BY x.continent, x.country;
这个方法的思路是:统计每个大洲内,字母顺序不晚于当前国家的数量,如果这个数量≤5,说明当前国家属于该大洲的前5个。不过要注意,这个方法在数据量大的时候效率会比窗口函数低很多,优先推荐窗口函数的方案。
内容的提问来源于stack exchange,提问作者Nick
相关产品推荐
相关产品推荐

