在Postgresql
(版本10)中,在sql之后,按avg_grade
选择所有行顺序。
-- query - students list, order by average grade,
select s.student_id, s.student_name, avg(ce.grade) as avg_grade
from students as s
left join course_enrollment as ce on s.student_id = ce.student_id
group by s.student_id
order by avg_grade desc NULLS LAST;
相关表格
学生:
create table students (
student_id bigserial not null primary key,
student_name varchar(200) not null,
created timestamp default CURRENT_TIMESTAMP not null
);
课程注册:
-- create table,
create table course_enrollment
(
course_id bigint not null,
student_id bigint not null,
grade float not null,
created timestamp default CURRENT_TIMESTAMP not null,
unique (course_id, student_id)
);
问题:
avg_grade
具有最高值的行的前n%(例如10%)?顺便说一句:
window functions
中的分区。group by
。答案 0 :(得分:2)
我将使用子查询:
select student_id, student_name, avg_grade, rank() over (order by avg_grade desc)
from (select s.student_id,
s.student_name,
avg(ce.grade) as avg_grade,
rank() over (order by avg(ce.grade) desc nulls last) as seqnum,
count(*) over () as cnt
from students s
left join
course_enrollment ce
on s.student_id = ce.student_id
group by s.student_id
) as ce_avg
where seqnum <= cnt * 0.1;
您可以改用其他窗口功能,例如NTILE()
和PERCENTILE_DISC()
。我更喜欢直接计算,因为它可以更好地控制联系的处理方式。
答案 1 :(得分:0)
尝试了一段时间后,我自己得到了一个丑陋而有效的解决方案。
select *, rank() over (order by avg_grade desc)
from (
select s.student_id, s.student_name, avg(ce.grade) as avg_grade
from students as s
left join course_enrollment as ce on s.student_id = ce.student_id
group by s.student_id
order by avg_grade desc nulls last
) as ce_avg
where avg_grade >= (
select ce_avg.avg_grade
from (
select s.student_id, s.student_name, avg(ce.grade) as avg_grade
from students as s
left join course_enrollment as ce on s.student_id = ce.student_id
group by s.student_id
order by avg_grade desc nulls last
) as ce_avg
limit 1 offset (select (count(*) * 0.1)::int from students) - 1
);
提示: