busidoway
@busidoway

Как вывести записи по ближайшей дате сгруппированные по категориям в MySQL 5.7?

Есть три таблицы: events, events_categories, event_category_joins (связующая). Необходимо вывести записи с ближайшей датой сгруппированные по категориям. Версия mysql: 5.7.

Пример вывода без группировки:
660fc7f119c89870223602.png

Код с группировкой:
select `events`.`id`,
	`events`.`date_public`,
	`event_categories`.`id` as `cat_id`,
    `event_categories`.`title` as `cat_title`
	from `events`
    inner join `event_category_joins` on `events`.`id` = `event_category_joins`.`event_id` 
    inner join `event_categories` on `event_categories`.`id` = `event_category_joins`.`event_category_id` 
    where `events`.`date_public` >= CURDATE()
    group by `event_categories`.`id`
    order by `events`.`date_public` asc;

Вывод:
660fc898b0e3c351816168.png

Выводит не по ближайшей дате, а по наименьшему events.id.

Пробовал группировать через join, находить наименьшую дату и сравнивать с датой основной таблицы :
select `events`.`id`,
	`events`.`date_public`,
	`event_categories`.`id` as `cat_id`,
    `event_categories`.`title` as `cat_title`
	from `events`
    inner join `event_category_joins` on `events`.`id` = `event_category_joins`.`event_id` 
    inner join `event_categories` on `event_categories`.`id` = `event_category_joins`.`event_category_id` 
    inner join (select `events`.`id` as `e_id`, min(`events`.`date_public`) as `min_date_public` 
                from `events` 
                inner join `event_category_joins` on `events`.`id` = `event_category_joins`.`event_id` 
                inner join `event_categories` on `event_categories`.`id` = `event_category_joins`.`event_category_id` 
                where `events`.`date_public` >= CURDATE()
                group by `event_categories`.`id`) as `events_cat` 
    on `events`.`id` = `events_cat`.`e_id`
    where `events`.`date_public` = `events_cat`.`min_date_public`
    order by `events`.`date_public` asc;


Выводит таким образом:
660fc9c3ebeda777443431.png

Как выловить-таки минимальную дату?
  • Вопрос задан
  • 66 просмотров
Решения вопроса 1
busidoway
@busidoway Автор вопроса
Кому интересно, вот решение:

SELECT 
    e.id,
    e.date_public,
    ec.id AS cat_id,
    ec.title AS cat_title
FROM 
    events e
INNER JOIN 
    event_category_joins ecj ON e.id = ecj.event_id
INNER JOIN 
    event_categories ec ON ec.id = ecj.event_category_id
INNER JOIN 
    (
        SELECT 
            ec.id AS cat_id, 
            MIN(e.date_public) AS min_date_public
        FROM 
            events e
        INNER JOIN 
            event_category_joins ecj ON e.id = ecj.event_id
        INNER JOIN 
            event_categories ec ON ec.id = ecj.event_category_id
        WHERE 
            e.date_public >= CURDATE()
        GROUP BY 
            ec.id
    ) ec_min ON ec.id = ec_min.cat_id AND e.date_public = ec_min.min_date_public
ORDER BY 
    e.date_public ASC;
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 2
@Akina
Сетевой и системный админ, SQL-программист.
На версии 8+ как-то так:
WITH cte AS (
    SELECT `events`.`id`,
           `events`.`date_public`,
	   `event_categories`.`id` as `cat_id`,
	   `event_categories`.`title` as `cat_title`
	   ROW_NUMBER() OVER (PARTITION BY `event_categories`.`id` ORDER BY `events`.`date_public` ASC) rn
    FROM `events`
    INNER JOIN `event_category_joins` ON `events`.`id` = `event_category_joins`.`event_id` 
    INNER JOIN `event_categories` ON `event_categories`.`id` = `event_category_joins`.`event_category_id` 
    WHERE `events`.`date_public` >= '2024-04-05 19:00:00'
--    WHERE `events`.`date_public` >= CURRENT_DATE
    )
SELECT id, date_public, cat_id, cat_title
FROM cte
WHERE rn = 1;
Ответ написан
Rsa97
@Rsa97
Для правильного вопроса надо знать половину ответа
"Ближайшая" - это только в будущее? Тогда
WHERE `date_public` = (
  SELECT MIN(`date_public`) FROM `events` WHERE `date_public` >= CURDATE()
)
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы