Как включить строку в запрос GROUP BY в MySQL?

У меня есть таблица для записи оценки, полученной учеником по предмету в конкретную дату. В таблице perf есть столбцы «id», «дата», «студент», «тема», «отметка».

Цель: я хочу сравнить оценку, полученную учеником, с самой высокой, самой низкой и средней оценкой класса по конкретному предмету за каждый день, используя один запрос, например:

SELECT date,mark,highest,lowest,avg,student FROM ....   

.... и получите такой результат:

дата отметка самый высокий самый низкий среднее студент 07.09.2021 73 82 58 69 2с3 09.09.2021 81 84 62 75 2с3 14 сентября 2021 г. 78 78 68 73 2с3 2021-09-17 75 89 59 73 2с3

Как мне достичь своей цели в одном заявлении?

Я открыт для промежуточных шагов, например, создания представлений.

Я использую MySQL 8.0.33.

Вот данные:

идентификатор дата студент предмет отметка 1 2021-09-6 а1б Английский 78 2 2021-09-7 а1б Искусство 63 3 8 сентября 2021 г. а1б Математика 67 4 09.09.2021 а1б Искусство 71 5 09.09.2021 а1б Английский 74 6 10.09.2021 а1б Математика 65 7 2021-09-13 а1б Английский 81 8 14 сентября 2021 г. а1б Искусство 68 9 2021-09-15 а1б Математика 70 10 16 сентября 2021 г. а1б Английский 79 11 2021-09-17 а1б Искусство 70 12 2021-09-17 а1б Математика 68 14 2021-09-6 2с3 Английский 68 15 07.09.2021 2с3 Искусство 73 16 8 сентября 2021 г. 2с3 Математика 57 17 09.09.2021 2с3 Искусство 81 18 09.09.2021 2с3 Английский 74 19 10.09.2021 2с3 Математика 55 20 2021-09-13 2с3 Английский 73 21 14 сентября 2021 г. 2с3 Искусство 78 22 2021-09-15 2с3 Математика 60 23 16 сентября 2021 г. 2с3 Английский 71 24 2021-09-17 2с3 Искусство 75 25 2021-09-17 2с3 Математика 58 26 2021-09-6 3d4 Английский 53 27 07.09.2021 3d4 Искусство 58 28 8 сентября 2021 г. 3d4 Математика 56 29 09.09.2021 3d4 Искусство 62 30 09.09.2021 3d4 Английский 54 31 10.09.2021 3d4 Математика 51 32 2021-09-13 3d4 Английский 51 33 14 сентября 2021 г. 3d4 Искусство 68 34 2021-09-15 3d4 Математика 60 35 16 сентября 2021 г. 3d4 Английский 58 36 2021-09-17 3d4 Искусство 59 37 2021-09-17 3d4 Математика 58 38 2021-09-6 4эф Английский 87 39 07.09.2021 4эф Искусство 82 40 8 сентября 2021 г. 4эф Математика 91 41 09.09.2021 4эф Искусство 84 42 09.09.2021 4эф Английский 79 43 10.09.2021 4эф Математика 81 44 2021-09-13 4эф Английский 73 45 14 сентября 2021 г. 4эф Искусство 78 46 2021-09-15 4эф Математика 82 47 16 сентября 2021 г. 4эф Английский 82 48 2021-09-17 4эф Искусство 89 49 2021-09-17 4эф Математика 92

Я могу получить высшую, низшую и среднюю оценку класса, используя 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   
дата отметка самый высокий самый низкий среднее 2021-09-06 Английский 87 53 72 07.09.2021 Искусство 82 58 69 2021-09-08 Математика 91 56 68 09.09.2021 Искусство 84 62 75 09.09.2021 Английский 79 54 70 10.09.2021 Математика 81 51 63

Попытка включить оценку и ученика в приведенный выше запрос дает бессмысленные результаты:

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  
дата предмет отметка самый высокий самый низкий среднее студент 16 сентября 2021 г. Английский 71 71 71 71 2с3 07.09.2021 Искусство 73 73 73 73 2с3 2021-09-13 Английский 73 73 73 73 2с3 2021-09-13 Английский 73 73 73 73 4эф 09.09.2021 Английский 74 74 74 74 а1б 09.09.2021 Английский 74 74 74 74 2с3 2021-09-17 Искусство 75 75 75 75 2с3 2021-09-06 Английский 78 78 78 78 а1б

Я пробовал несколько вещей, но мне удалось объединить оценку, высшую, самую низкую, среднюю, студентку в один результат, когда я указываю студента, предмет и дату следующим образом, но это слишком специфично и не то, что я хочу:

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 
дата отметка самый высокий самый низкий среднее 07.09.2021 73 82 58 69

Пожалуйста, отредактируйте свой вопрос и постарайтесь отформатировать его так, чтобы его можно было прочитать. Ваши операторы SQL должны быть отформатированы как код, а данные должны быть в таблицах. Вы можете получить помощь по форматированию, нажав ? на панели инструментов во время редактирования.

Ken White 06.08.2024 00:10
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
В последние годы архитектура микросервисов приобрела популярность как способ построения масштабируемых и гибких приложений. Laravel , популярный PHP...
Как построить CRUD-приложение в Laravel
Как построить CRUD-приложение в Laravel
Laravel - это популярный PHP-фреймворк, который позволяет быстро и легко создавать веб-приложения. Одной из наиболее распространенных задач в...
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
В предыдущем посте мы создали функциональность вставки и чтения для нашей динамической СУБД. В этом посте мы собираемся реализовать функции обновления...
Документирование API с помощью Swagger на Springboot
Документирование API с помощью Swagger на Springboot
В предыдущей статье мы уже узнали, как создать Rest API с помощью Springboot и MySql .
Роли и разрешения пользователей без пакета Laravel 9
Роли и разрешения пользователей без пакета Laravel 9
Этот пост изначально был опубликован на techsolutionstuff.com .
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
В предыдущей статье мы завершили установку базы данных, для тех, кто не знает.
2
1
65
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Доказательство работы Ввод и вывод 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 :)

Выдает ошибку 1054 — Неизвестный столбец «s.mark» в пункте «where». Удаление строки «ГДЕ p.mark = s.mark» убирает ошибку. Однако полученное решение возвращает повторяющиеся строки. Изменение «ВЫБРАТЬ дату, тему, ...» на «ВЫБРАТЬ ОТЛИЧНЫЕ дату, тему, ...» удаляет дубликаты. Судя по всему, решение на вашем GitHub не выдает ошибку 1054, хотя все равно возвращает дубликаты.

user3245096 09.08.2024 15:53

Используйте 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

Спасибо. Выдает ошибку 1054 — Неизвестный столбец «c.mark» в «списке полей». Отлично работает при изменении «c.mark» на «mark» в списке полей и удалении «WHERE c.mark = p.mark»

user3245096 09.08.2024 15:35

Возможно, вы можете использовать оконную функцию 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 

результат:

идентификатор дата студент предмет отметка самый высокий самый низкий AVG 1 2021-09-06 а1б Английский 78 87 53 72 14 2021-09-06 2с3 Английский 68 87 53 72 38 2021-09-06 4эф Английский 87 87 53 72 26 2021-09-06 3d4 Английский 53 87 53 72 2 07.09.2021 а1б Искусство 63 82 58 69 ...

Это простое использование оконных функций. может помочь тебе.

Аккуратный. Работает идеально. Однако реализация, похоже, занимает вдвое больше времени, чем решения, представленные здесь до сих пор.

user3245096 09.08.2024 15:41
Ответ принят как подходящий
SELECT
a.DATE,
b.lowest,
b.highest,
b.avg,
a.student,
a.mark
FROM perf a
LEFT JOIN (
SELECT
DATE,
SUBJECT, 
MIN(mark) AS lowest,
MAX(mark) AS highest,
AVG(mark) AS AVG
FROM perf
GROUP BY DATE,SUBJECT ) b ON a.date = b.date AND a.subject = b.subject

Работает идеально. Спасибо.

user3245096 09.08.2024 15:36

Другие вопросы по теме