@frmax
человек

Как выполнить туже операцию 1 запросом?

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

Задача:
Есть таблица `course` (`currency` enum(‘usd’, ‘eur’, ...), `price` float, `created_at` datetime) с курсами валют. В таблицу идет запись, как только изменился курс, путем добавления новой записи в конец. Курс по одной валюте может не меняться несколько дней, а по другой изменяться каждую минуту. Необходимо вывести актуальный курс валют. Список валют заранее не известен.

Попытки
sqlfiddle.com/#!9/172f58/1

Код который делает что мне нужно
SELECT n.* 
FROM course n 
INNER JOIN (
SELECT id, MAX(created_at) AS created_at
  FROM course GROUP BY currency  
) AS max USING (created_at)
;


Структура
CREATE TABLE IF NOT EXISTS `course` (
  `id` int(6) unsigned NOT NULL,
  `price` int(3) unsigned NOT NULL,
  `currency` enum('usd', 'rub') NOT NULL,
  `created_at` datetime,
  PRIMARY KEY (`id`)
) DEFAULT CHARSET=utf8;
INSERT INTO `course` (`id`, `price`, `currency`, `created_at`) VALUES
  (1, 1, 'usd', CURDATE()),
  (2, 6, 'usd', date('2020-11-11')),
  (3, 3, 'usd', date('2020-12-11')),
  (4, 2, 'rub', date('2019-11-11')),
  (5, 66, 'rub', date('2020-11-14')),
  (6, 3, 'rub', now());


Есть идеи?
  • Вопрос задан
  • 131 просмотр
Решения вопроса 1
Только уже указанный вариант с подзапросом возможен, так как нет возможности использовать группировку и не участвующие в группировке или неаггрегированные поля. Единственное что, выгоднее будет использовать первичный ключ для JOIN
SELECT n.* FROM course n
JOIN (SELECT MAX(created_at) created_at FROM course GROUP BY currency) m
USING(created_at)


Одним запросом, судя по explain, значительно дороже будет такой запрос
SELECT n.* FROM course n
LEFT JOIN course m
ON n.currency = m.currency AND n.created_at < m.created_at
WHERE m.id IS NULL
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
@MaximaXXl
Это больше на изврат похоже, условие без подзапросов ...
но вот:
select distinct
FIRST_VALUE(currency) OVER (PARTITION BY currency ORDER BY created_at desc) currency,
FIRST_VALUE(price)    OVER (PARTITION BY currency ORDER BY created_at desc) price
       from course

Данных нет, не проверял, но должно работать
Ответ написан
Ваш ответ на вопрос

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

Войти через центр авторизации
Похожие вопросы