简体   繁体   English

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

[英]Find Nth value and average value corresponding to each group in SQL

I have a table with name and grades for some users我有一些用户的姓名和成绩表

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

I want an output table grouped by the name, along with the average grade and the nth lowest value for each name.我想要一个按名称分组的 output 表,以及每个名称的平均成绩和第 n 个最低值。

I tried to use window function nth_value() but I get an error when I try to execute the query (n = 2 here)我尝试使用 window function 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 42803:“grades.grade”列必须出现在 GROUP BY 子句中或用于聚合 function

What is the correct way of writing such a query?编写此类查询的正确方法是什么?

Use conditional aggregation:使用条件聚合:

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() is a window function not an aggregation function. nth_value()window function 不是聚合 function。

You can also use arrays:您也可以使用 arrays:

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;

In your code, the value you are suggesting is the second smallest grade.在您的代码中,您建议的值是第二小的等级。 If you want the second largest, use desc for the order by s.如果您想要第二大,请使用desc order by

Starting from your current attempt, a simple option uses a window average and distinct :从您当前的尝试开始,一个简单的选项使用 window average 和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;

Alternatively, you can rank grades in a subquery, and use conditional aggregation in the outer query:或者,您可以在子查询中对成绩进行排名,并在外部查询中使用条件聚合:

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;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM