/ / Використання max () в SQL-sql, базі даних, виберіть

Використовуючи max () у SQL-sql, базі даних, виберіть

Одна частина мого домашнього завдання полягає в тому, щоб знайти студента з найвищим середнім значенням з кожного відділу.

QUERY:

SELECT g.sid as studentID, s.sfirstname, s.dcode, AVG(grade) as average
FROM studentgrades g, student s
WHERE g.sid = s.sid
GROUP BY s.sid

RESULT:

1   Robert  ger 80.0000
2   Julie   sta 77.0000
3   Michael csc 84.0000
4   Julia   csc 100.0000
5   Patric  csc 86.0000
6   Jill    sta 74.5000

Щоб відповісти на питання, я запустив запит

SELECT dcode, averages.sfirstName, MAX(averages.average)
FROM (
SELECT g.sid as studentID, s.sfirstname, s.dcode, AVG(grade) as average
FROM studentgrades g, student s
WHERE g.sid = s.sid
GROUP BY s.sid) averages
GROUP BY dcode

RESULT:

csc Michael 100.0000
ger Robert  80.0000
sta Julie   77.0000

Хоча середні значення правильні, імена не є! Джулія - ​​це той, хто має в середньому 100 в CSC, то чому Майкл з'являється?


Ось приклад:

студент проходить курси та отримує оцінки для цих курсів. EG:

student1 from dept1 took course A and got grade 80
student1 from dept1 took course B and got grade 90
student2 from dept1 took course C and got grade 100
student3 from dept2 took course X and got grade 90

ПІСЛЯ ПЕРШИХ ЗАПИТІВ, ми отримуємо середні значення для кожного учня

student 1 from dept1 has average 85
student 2 from dept1 has average 100
student 3 from dept2 has average 90

Тепер ми знаходимо студент з найвищим середнім по кожному відділу

dept1, student2, 100
dept2, student3, 90

Відповіді:

3 для відповіді № 1

Це має зробити це (і він використовує GROUP BY відповідно до стандарту SQL, а не тим, як MySQL реалізує його)

select s.sid,
s.sfirstname,
s.dcode,
ag.avg_grade
from students s
join (select sid, avg(grade) as avg_grade
from studentgrades
group by sid) ag on ag.sid = s.sid
join (select s.dcode,
max(avg_grade) max_avg_grade
from students s
join (select sid, avg(grade) as avg_grade
from studentgrades
group by sid) ag on ag.sid = s.sid
group by s.dcode) mag on mag.dcode = s.dcode and mag.max_avg_grade = ag.avg_grade
order by mag.avg_grade;

Як це працює?

Це накопичує результат в кілька кроків. Спочатку він обчислює середній бал для кожного студента:

select sid, avg(grade) as avg_grade
from studentgrades
group by sid

Виходячи з результату цього твердження, ми можемо обчислити макс. Середня оцінка:

select s.dcode,
max(avg_grade) max_avg_grade
from students s
join (select sid, avg(grade) as avg_grade
from studentgrades
group by sid) ag on ag.sid = s.sid
group by s.dcode

Тепер ці два результати приєднуються до столу студентів. Для полегшення читання припустимо, є вигляд називається average_grades (перша заява) і max_average_grades (другий).

Остаточний висновок в основному робить це тоді:

select s.sid,
s.sfirstname,
s.dcode,
ag.avg_grade
from students s
join avg_grades ag on ag.sid = s.sid
join max_avg_grades mag
on mag.dcode = s.dcode
and mag.max_avg_grade = ag.avg_grade;

Реальний (перший у моєму відповіді) просто замінює імена avg_grades і max_avg_grades з вибраними я показав. Ось чому це виглядає так складно.

Рішення в стандартному SQL, яке трохи читається

У стандартному SQL це можна виразити за допомогою загальної вираз таблиці, яка робить її трохи читабельною (але по суті однакова)

with avg_grades (sid, avg_grade) as (
select sid, avg(grade) as avg_grade
from studentgrades
group by sid
),
max_avg_grades (dcode, max_avg_grade) as (
select s.dcode, max(avg_grade) max_avg_grade
from students s
join avg_grades ag on ag.sid = s.sid
group by s.dcode
)
select s.sid,
s.sfirstname,
s.dcode,
ag.avg_grade
from students s
join avg_grades ag on ag.sid = s.sid
join max_avg_grades mag on mag.dcode = s.dcode and mag.max_avg_grade = ag.avg_grade;

Але MySQL - це одна з небагатьох СУБД, які не підтримують це, тому вам доведеться дотримуватися початкового твердження.

Стандартний SQL-рішення, що вимагає менш виведених таблиць

У стандартному SQL він може бути написаний навіть трохи коротше, використовуючи вікна функції для розрахунку рангу всередині відділу (знову ж таки це не працює в MySQL)

with avg_grades (sid, avg_grade) as (
select sid, avg(grade) as avg_grade
from studentgrades
group by sid
)
select sid,
sfirstname,
dcode,
avg_grade
from (
select s.sid,
s.sfirstname,
s.dcode,
ag.avg_grade,
rank() over (partition by s.dcode order by ag.avg_grade desc) as rnk
from students s
join avg_grades ag on ag.sid = s.sid
) t
where rnk = 1;

0 для відповіді № 2

Оновити запит, щоб використовувати HAVING пункт нижче:

   SELECT dcode, averages.sfirstName, averages.average
FROM (
SELECT g.sid as studentID, s.sfirstname, s.dcode, AVG(grade) as average
FROM studentgrades g, student s
WHERE g.sid = s.sid
GROUP BY s.sid) averages
GROUP BY dcode
HAVING MAX(averages.average) = averages.average

0 для відповіді № 3

Є багато різних рішень. Можливо, цей простіше зрозуміти:

/* create a new temporariy table of student performance. to keep the code clean and the performance better */
INSERT INTO studentperformance (studentID, sfirstname, dcode, average)
SELECT g.sid as studentID
, s.sfirstname
, s.dcode
, AVG(grade) as average
FROM studentgrades g, student s
WHERE g.sid = s.sid
GROUP BY s.sid;

/* best grades for each department */
INSERT INTO bestgrades (best_average_per_department)
SELECT (dcode + "|" + MAX(average)) as best_average_per_department /* important string. maybe one has to cast the max(average) to string for this to work */
FROM studentperformance
GROUP BY dcode; /* important groub by ! */

/* get all the students who are best in each department */
SELECT a.studentID
, a.sfirstname
, a.dcode
, a.average
FROM studentperformance as a
JOIN bestgrades as b on (a.dcode + "|" + a.average) = b.best_average_per_department;