Запрос Mysql, возвращающий последний результат для каждого элемента

#mysql #sql

#mysql #sql

Вопрос:

Мне трудно разобраться в том, что, по-видимому, должно быть простым запросом.

Итак, допустим, у нас есть таблица, которая отслеживает количество виджетов / воздушных шаров в каждом хранилище по дате. Как бы вы получили список магазинов и их последнее количество виджетов / воздушных шаров?

т. е.

 mysql> SELECT * FROM inventory;
 ---- ------------ ------- --------- --------- 
| id | invDate    | store | widgets | balloons|
 ---- ------------ ------- --------- --------- 
|  1 | 2011-01-01 |     3 |      50 |      35 |
|  2 | 2011-01-04 |     2 |      50 |      35 |
|  3 | 2013-07-04 |     3 |      12 |      78 |
|  4 | 2020-07-04 |     2 |      47 |      18 |
|  5 | 2020-08-06 |     2 |      16 |    NULL |
 ---- ------------ ------- --------- --------- 
5 rows in set (0.00 sec)

  

Хотелось бы, чтобы в таблице результатов были перечислены все хранилища и их последний инвентарь виджетов / шариков

магазин, последние виджеты, последние шары

  ------- ----------- --------- 
| store |   widgets | baloons |
 ------- ----------- --------- 
|     2 |        16 |    NULL |
|     3 |        12 |      78 |
 ------- ----------- --------- 
  

или возьмите последнее ненулевое значение для balloons.

Комментарии:

1. Добавьте ПОРЯДОК По invDate DESC и ГРУППУ По хранилищу в конец вашего запроса.

2. @jhilgeman: Это не так просто

3. @meccooll: Какую версию MySQL вы используете?

4. Запущено несколько версий, и их можно обновить, если есть элегантное решение для более новой версии, но одним из старых экземпляров является mysqld версии 5.7.31-0ubuntu0.16.04.1 для Linux на x86_64

Ответ №1:

Это работает для всех версий MySQL

 select i.*
from inventory i
join
(
  select store, max(invDate) as maxDate
  from inventory
  group by store
) tmp on tmp.store = i.store 
     and tmp.maxDate = i.invDate
  

С MySQL 8 вы можете выполнять оконные функции:

 with cte as
(
   select store, widgets, balloons, 
          ROW_NUMBER() OVER(PARTITION BY store ORDER BY invDate desc) AS rn
   from inventory
)
select * from cte where rn = 1
  

Комментарии:

1. Вот и все! Приятно сознавать, что не было какой-то простой функции, которую я упускал. Спасибо

Ответ №2:

Вы можете использовать коррелированный подзапрос, чтобы получить последнюю запись для каждого хранилища

 select i.*
from inventory i
where i.invDate = (
    select max(invDate)
    from inventory
    where i.store = store
)
order by i.store
  

ДЕМОНСТРАЦИЯ

Комментарии:

1. @juergend вот так sqlfiddle.com /#!9/f845d7/1 ? Я действительно не понимаю вашего заявления, оно должно сработать, если дата 2 или более хранилищ одинакова из-за коррелированного запроса