在SQL中查找每个组对应的第N个值和平均值
Posted
技术标签:
【中文标题】在SQL中查找每个组对应的第N个值和平均值【英文标题】:Find Nth value and average value corresponding to each group in SQL 【发布时间】:2021-02-25 22:00:51 【问题描述】:我有一张表,上面有一些用户的姓名和成绩
CREATE TABLE grades (name varchar(100), grade integer);
insert into grades
values
('Bob', 12),
('Bob', 13),
('Bob', 23),
('Bob', 17),
('James', 15),
('James', 27),
('Nick ', 18),
('Nick ', 16),
('Nick ', 22),
('Nick ', 32),
('Nick ', 19);
我想要一个按名称分组的输出表,以及每个名称的平均成绩和第 n 个最低值。
我尝试使用窗口函数nth_value(),但尝试执行查询时出现错误(此处为 n = 2)
select name, avg(grade), nth_value(grade, 2) over(partition by name
order by grade
Range BETWEEN
UNBOUNDED PRECEDING AND
UNBOUNDED FOLLOWING)
from grades group by name;
错误、警告:
42803:列“grades.grade”必须出现在 GROUP BY 子句中或用于聚合函数中
编写这样一个查询的正确方法是什么?
【问题讨论】:
【参考方案1】:使用条件聚合:
select name, avg(grade),
max(grade) filter (where seqnum = 2)
from (select g.*,
row_number() over (partition by name order by grade) as seqnum
from grades g
) g
group by name;
nth_value()
是一个窗口 函数而不是聚合函数。
你也可以使用数组:
select name, avg(grade),
(array_agg(grade order by grade))[2]
from (select g.*,
row_number() over (partition by name order by grade) as seqnum
from grades g
) g
group by name;
在您的代码中,您建议的值是第二小的等级。如果您想要第二大,请使用desc
作为order by
s。
【讨论】:
【参考方案2】:从您当前的尝试开始,一个简单的选项使用窗口平均值和distinct
:
select distinct
name,
avg(grade) over(partition by name) avg_grade,
nth_value(grade, 2) over(
partition by name
order by grade
range between unbounded preceding and unbounded following
) grade_n2
from grades;
或者,您可以在子查询中对成绩进行排名,并在外部查询中使用条件聚合:
select name, avg(grade) avg_grade, max(grade) filter(where rn = 2) grade_n2
from (
select g.*, row_number() over(partition by name order by grade) rn
from grades g
) g
group by name;
【讨论】:
以上是关于在SQL中查找每个组对应的第N个值和平均值的主要内容,如果未能解决你的问题,请参考以下文章