求SQL中每组对应的第N个值和平均值

Find Nth value and average value corresponding to each group in SQL

我有一个 table 有一些用户的名字和成绩

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);

我想要一个按姓名分组的输出 table,以及每个姓名的平均成绩和第 n 个最低值。

我尝试使用 window 函数 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;

Error(s), warning(s):

42803: column "grades.grade" must appear in the GROUP BY clause or be used in an aggregate function

写这样一个查询的正确方法是什么?

使用条件聚合:

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() 是一个 window 函数而不是聚合函数。

你也可以使用数组:

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

从您当前的尝试开始,一个简单的选项使用 window 平均值和 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;