SQL Server查询:获取NBA每年选秀最矮球员的姓名及身高
问题描述
我正在编写SQL Server查询,想要获取NBA每年选秀中最矮球员的姓名及身高。目前使用以下查询语句:
SELECT a.player_height, a.player_name, a.draft_year FROM NBA.dbo.Players a WHERE a.draft_year IS NOT NULL GROUP BY a.draft_year ORDER BY a.draft_year;
其中player_name数据类型为nvarchar,draft_year和player_height为float。执行时出现错误:
Column 'NBA..Players.player_height' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
需要获取每年选秀中最矮球员的姓名和身高,如何修正该查询,或是否有更优写法?
解决方案
方法一:窗口函数写法(推荐,SQL Server 2008+支持)
窗口函数可以直接对每年的球员按身高排序,标记出最矮的球员,还能灵活处理并列情况:
保留同年所有并列最矮的球员
如果某一年有多个球员身高相同且都是当年最矮,用RANK()会把这些球员都返回:
SELECT player_height, player_name, draft_year FROM ( SELECT player_height, player_name, draft_year, -- 按选秀年份分组,每组内按身高升序排名 RANK() OVER(PARTITION BY draft_year ORDER BY player_height ASC) AS height_rank FROM NBA.dbo.Players WHERE draft_year IS NOT NULL ) AS ranked_players WHERE height_rank = 1 ORDER BY draft_year;
仅返回同年一个最矮球员(若有并列随机选)
如果只需要每个年份返回一个球员,把RANK()换成ROW_NUMBER()即可,它会给每个分组内的球员唯一排序:
SELECT player_height, player_name, draft_year FROM ( SELECT player_height, player_name, draft_year, ROW_NUMBER() OVER(PARTITION BY draft_year ORDER BY player_height ASC) AS height_rank FROM NBA.dbo.Players WHERE draft_year IS NOT NULL ) AS ranked_players WHERE height_rank = 1 ORDER BY draft_year;
方法二:子查询关联写法(兼容旧版SQL Server)
先通过子查询计算出每年的最矮身高,再关联原表找到对应球员:
SELECT p.player_height, p.player_name, p.draft_year FROM NBA.dbo.Players p INNER JOIN ( -- 先获取每年的最矮身高 SELECT draft_year, MIN(player_height) AS min_height FROM NBA.dbo.Players WHERE draft_year IS NOT NULL GROUP BY draft_year ) AS year_min ON p.draft_year = year_min.draft_year AND p.player_height = year_min.min_height WHERE p.draft_year IS NOT NULL ORDER BY p.draft_year;
这种写法同样会返回同年所有并列最矮的球员。
错误原因说明
原查询报错是因为SQL Server的分组规则:当使用GROUP BY时,SELECT语句中的非聚合列必须要么出现在GROUP BY子句中,要么被聚合函数(如MIN、MAX)包裹。你原来的查询只按draft_year分组,但player_height和player_name既不在分组列里,也没有用聚合函数处理,因此不符合语法要求。
内容的提问来源于stack exchange,提问作者coverc23

