У меня есть таблица для записи оценки, полученной учеником по предмету в конкретную дату. В таблице perf есть столбцы «id», «дата», «студент», «тема», «отметка».
Цель: я хочу сравнить оценку, полученную учеником, с самой высокой, самой низкой и средней оценкой класса по конкретному предмету за каждый день, используя один запрос, например:
SELECT date,mark,highest,lowest,avg,student FROM ....
.... и получите такой результат:
Как мне достичь своей цели в одном заявлении?
Я открыт для промежуточных шагов, например, создания представлений.
Я использую MySQL 8.0.33.
Вот данные:
Я могу получить высшую, низшую и среднюю оценку класса, используя GROUP BY следующим образом:
SELECT date,subject,MAX(mark) AS highest, MIN(mark) AS lowest, FORMAT(AVG(mark),0) AS avg FROM perf GROUP BY date,subject
Попытка включить оценку и ученика в приведенный выше запрос дает бессмысленные результаты:
SELECT date,subject,mark,MAX(mark) AS highest, MIN(mark) AS lowest, FORMAT(AVG(mark),0) AS avg,student FROM perf GROUP BY date,subject,mark,student
Я пробовал несколько вещей, но мне удалось объединить оценку, высшую, самую низкую, среднюю, студентку в один результат, когда я указываю студента, предмет и дату следующим образом, но это слишком специфично и не то, что я хочу:
SELECT (SELECT date FROM perf WHERE student='2c3' AND subject='Art' AND date='2021-09-07') AS date,
(SELECT mark FROM perf WHERE student='2c3' AND subject='Art' AND date='2021-09-07') AS mark,
(SELECT MAX(mark) FROM perf WHERE subject='Art' AND date='2021-09-07') AS highest,
(SELECT MIN(mark) FROM perf WHERE subject='Art' AND date='2021-09-07') AS lowest,
(SELECT FORMAT(AVG(mark),0) FROM perf WHERE subject='Art' AND date='2021-09-07') AS avg
🤔 А знаете ли вы, что...
MySQL предоставляет средства для оптимизации запросов с использованием индексов и профилирования.
Доказательство работы Ввод и вывод GitHub из компилятора SQL Online: https://gist.github.com/xentzenith/ccdcc3e11f377195645cf2db8a4dccf0
Для достижения цели сравнения оценки, полученной учащимся, с самой высокой, самой низкой и средней оценкой класса по конкретному предмету за каждый день, вы можете использовать комбинацию оконных функций и подзапросов.
WITH stats AS (
SELECT
date,
subject,
MAX(mark) OVER (PARTITION BY date, subject) AS highest,
MIN(mark) OVER (PARTITION BY date, subject) AS lowest,
AVG(mark) OVER (PARTITION BY date, subject) AS avg
FROM perf
)
SELECT
p.date,
p.mark,
s.highest,
s.lowest,
ROUND(s.avg, 0) AS avg,
p.student
FROM perf p
JOIN stats s ON p.date = s.date AND p.subject = s.subject
WHERE p.mark = s.mark;
CTE статистики вычисляет самые высокие, самые низкие и средние оценки для каждого предмета на каждую дату, используя оконные функции (MAX(), MIN(), AVG()). Предложение PARTITION BY указывает группу строк, к которым применяется агрегатная функция. Это должно работать для вас, если вы используете соответствующую версию SQL :)
Используйте CTE, чтобы вычислить общие значения и присоединиться к ним:
with cte as (
SELECT
date,
subject,
MAX(mark) AS highest,
MIN(mark) AS lowest,
FORMAT(AVG(c.mark), 0) AS avg
FROM perf
GROUP BY date, subject
)
SELECT
c.date,
c.subject,
p.mark,
c.highest,
c.lowest,
c.avg,
p.student
FROM perf p
JOIN cte c ON c.date = p.date
AND c.subject = p.subject
Возможно, вы можете использовать оконную функцию mysql8, она может собирать данные из нескольких измерений в одной строке.
SELECT
p.*,
MAX(p.mark) over(PARTITION BY p.date, p.subject) AS highest,
MIN(p.mark) over(PARTITION BY p.date, p.subject) AS lowest,
format(AVG(p.mark) over(PARTITION BY p.date, p.subject), 0) AS AVG
FROM perf p
результат:
Это простое использование оконных функций. может помочь тебе.