#mysql #sql #group-by
#mysql #sql #группировка по
Вопрос:
Предположим, у нас есть таблица:
SELECT * FROM users_to_courses;
--------- ----------- ------------ ---------
| user_id | course_id | pass_date | file_id |
--------- ----------- ------------ ---------
| 1 | 1 | 2014-01-01 | 1 |
| 1 | 1 | 2014-01-01 | 2 |
| 1 | 1 | 2014-02-01 | 3 |
| 1 | 1 | 2014-02-01 | 4 |
--------- ----------- ------------ ---------
Схема:
CREATE TABLE `users_to_courses` (
`user_id` int(10) unsigned NOT NULL,
`course_id` int(10) unsigned NOT NULL,
`pass_date` date NOT NULL,
`file_id` int(10) unsigned NOT NULL,
PRIMARY KEY (`user_id`, `course_id`, `pass_date`, `file_id`),
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Один пользователь может проходить определенный курс несколько раз, и каждый раз, когда он проходит, может быть сгенерировано несколько сертификатов. user_id
и course_id
сохраните ссылки на таблицы users и courses. file_id — таблица файлов, в которой хранится информация о файлах сертификатов.
В нашем примере пользователь № 1 дважды прошел курс № 1, и каждый раз было выдано 2 сертификата: всего 4 записи.
Как я могу получить эти данные: для user_id = 1 для каждого курса получите MAX (pass_date) и все файлы, прикрепленные к этой дате. Пока я мог получить только это:
SELECT
users_to_courses.course_id,
MAX(users_to_courses.pass_date) AS max_passed_date,
GROUP_CONCAT(users_to_courses.file_id SEPARATOR ',') AS files
FROM
users_to_courses
WHERE
users_to_courses.user_id=1
GROUP BY
users_to_courses.course_id;
----------- ----------------- ---------
| course_id | max_passed_date | files |
----------- ----------------- ---------
| 1 | 2014-02-01 | 1,2,3,4 |
----------- ----------------- ---------
Мне нужно это:
----------- ----------------- ---------
| course_id | max_passed_date | files |
----------- ----------------- ---------
| 1 | 2014-02-01 | 3,4 |
----------- ----------------- ---------
Я думаю, для этого требуется составная GROUP BY .
Комментарии:
1. Похоже, что ваши данные говорят о том, что он прошел курс 4 раза, дважды в два разных дня. Это допустимый случай? Если это так, вам, вероятно, понадобится как минимум дополнительная таблица, чтобы иметь возможность корректно поддерживать ваши данные…
2. @Clockwork-Muse нет, он прошел дважды и получил 2 сертификата за каждый проход. Как вы думаете, эти данные можно нормализовать?
3. Проблема в том, что на основе только этой таблицы ее интерпретация неоднозначна — любой способ просмотра является правильным, вам нужна метаинформация (например, знание того, что люди не могут проходить один и тот же тест дважды в один и тот же день). Если вы можете проходить тест только один раз в день, все в порядке. Если вы можете использовать его более одного раза, вам нужен какой-то
attemptId
столбец, что, вероятно, означает новый файл перекрестных ссылок между этим иfile_id
.
Ответ №1:
Попробуйте следующий запрос, сначала он получает максимальную дату для всех записей, а затем мы можем объединить только эти записи во внешнем запросе. Вы можете использовать один и тот же запрос для нескольких пользователей, добавив group by utc.user_id
SELECT
utc.course_id,
mdt.maxDate AS max_passed_date,
GROUP_CONCAT(utc.file_id SEPARATOR ',') AS files
FROM
users_to_courses utc
join
(SELECT MAX(pass_date) AS maxDate, course_id cId, user_id uId
FROM users_to_courses GROUP BY user_id, course_id) AS mdt
ON
mdt.uId = utc.user_id
AND
mdt.cId = utc.course_id
AND
mdt.maxDate = utc.pass_date
WHERE
utc.user_id=1
GROUP BY
utc.course_id;
Комментарии:
1. Интересно, не эффективнее ли поместить WHERE в подзапрос? И исключение maxdate из GROUP BY немного неприятно.
2. @Strawberry Если вы можете предложить более эффективное решение, пожалуйста, опубликуйте его в качестве другого ответа.