Мне нужна помощь в написании эффективного запроса, чтобы найти список первоочередных задач (учащихся с максимальным общим количеством баллов в каждом классе), когда нам дают индивидуальные оценки по каждому предмету в разных классах. Мы должны вернуть 3 столбца: класс, имя topper_student и topper_student_total.

Я использовал несколько подзапросов, чтобы найти решение. Я уверен, что были бы намного лучшие реализации, доступные для этой проблемы (возможно через объединения или оконные функции?).

Входную таблицу и мое решение можно найти по ссылке SQL Fiddle.

http://www.sqlfiddle.com/#!15/2919e/1/0

Таблица ввода:

enter image description here

1
Shadab Azeem 28 Янв 2020 в 13:37

3 ответа

Лучший ответ

Было бы понятнее использовать временные таблицы для хранения результатов по пути и обеспечения возможности отслеживания результатов, но решение может быть достигнуто с помощью одного запроса:

WITH student_marks AS (
    SELECT Class_num, Name, SUM(Marks) AS student_total_marks
    FROM School
    GROUP BY Class_num, Name
) 
SELECT Class_num, Name, student_total_marks 
FROM ( 
    SELECT Class_num, Name, student_total_marks, ROW_NUMBER() OVER(partition by Class_num order by student_total_marks desc, Class_num) AS beststudentfirst
    FROM student_marks
) A
WHERE A.beststudentfirst = 1

Запрос в выражении WITH вычисляет сумму баллов для каждого учащегося в классе. На этом этапе subject больше не требуется. Результат временно сохраняется в student_marks .

Затем нам нужно создать счетчик (beststudentfirst), используя ROW_NUMBER для нумерации общих оценок от самых высоких до самых низких в каждом классе (упорядочить по student_total_marks desc, Class_num). Счетчик следует перезапускать каждый раз при изменении класса (разделение по порядку Class_num).

Из этого последнего результата нам нужен только счетчик (beststudentfirst) со значением один. Это лучший ученик в каждом классе.

1
davidc2p 28 Янв 2020 в 14:38
select Class_num,[Name],total_marks from
(
select Row_number() over (partition by class_num order by Class_num,SUM(Marks) desc) as 
[RN],Class_num,[Name],SUM(Marks) as total_marks
from School
group by Class_num,[Name]
)A
where RN=1
-1
Atk 28 Янв 2020 в 11:41

Оконные функции - самый естественный способ приблизиться к этому. Если вам всегда нужно ровно три ученика, используйте row_number():

select Class_num, Name, total_marks
from (select name, class_num, sum(marks) as total_marks,
             row_number() over (partition by class_num order by sum(marks) desc) as seqnum
      from School
      group by Class_num, Name
     ) s
where seqnum <= 1
order by class_num, total_marks desc;

Если вы хотите учесть связи, используйте rank() или dense_rank().

Здесь - скрипта SQL.

0
Gordon Linoff 30 Янв 2020 в 11:25