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

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

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

Пример вывода без группировки

Код с группировкой:

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;

Выводит таким образом (не по ближайшей дате, а по наименьшему 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;

Выводит так:

введите сюда описание изображения

В идеале нужно, чтобы вывелись записи по следующим id: 101, 102, 106, 109, 110.


Ответы (1 шт):

Автор решения: ValNik

Посмотрите пример:

select *
from event_categories ec
inner join (
  select *
    ,row_number()over(partition by ecj.event_category_id order by e.date_public) rn
  from events e
  inner join event_category_joins ecj on ecj.event_id=e.id
  where e.date_public>curdate()
  ) oe on oe.event_category_id=ec.id
where rn=1
id title id date_public event_id event_category_id rn
1 Вебинар 106 2024-04-24 106 1 1
2 Онлайн курс 104 2024-09-19 104 2 1
3 Видеокурс 110 2024-04-10 110 3 1
5 Стажировка 102 2024-07-09 102 5 1
6 Практикум 101 2024-05-16 101 6 1
→ Ссылка