Как получить первую и последнюю запись сгруппированной записи в MySQL-запросе с помощью агрегатных функций?
Я пытаюсь получить первую и последнюю запись "сгруппированной" записи.
Точнее, я делаю запрос вроде этого
SELECT MIN(low_price), MAX(high_price), open, close
FROM symbols
WHERE date BETWEEN(.. ..)
GROUP BY YEARWEEK(date)
но я бы хотел получить первую и последнюю запись группы. Это можно сделать, выполнив множество запросов, но у меня довольно большая таблица.
Есть ли способ (по меньшей мере, время обработки), чтобы сделать это с MySQL?
Ответы
Ответ 1
Вы хотите использовать GROUP_CONCAT
и SUBSTRING_INDEX
:
SUBSTRING_INDEX( GROUP_CONCAT(CAST(open AS CHAR) ORDER BY datetime), ',', 1 ) AS open
SUBSTRING_INDEX( GROUP_CONCAT(CAST(close AS CHAR) ORDER BY datetime DESC), ',', 1 ) AS close
Это позволяет избежать дорогостоящих подзапросов, и я считаю его более эффективным для этой конкретной проблемы.
Просмотрите страницы руководства для обеих функций, чтобы понять их аргументы, или посетите эту статью, которая включает пример того, как сделать преобразование таймфрейма в MySQL для получения дополнительных пояснений.
Ответ 2
Попробуйте это, чтобы начать с...:
Select YearWeek, Date, Min(Low_Price), Max(High_Price)
From
(Select YEARWEEK(date) YearWeek, Date, LowPrice, High_Price
From Symbols S
Where Date BETWEEN(.. ..)
GROUP BY YEARWEEK(date)) Z
Group By YearWeek, Date
Ответ 3
Вот большое конкретное решение этой конкретной проблемы:
http://topwebguy.com/first-and-last-in-mysql-a-working-solution/
Это почти так же просто, как использование FIRST и LAST в MySQL.
Я буду включать код, который фактически предоставляет решение, но вы можете посмотреть весь текст:
SELECT
word ,
(SELECT a.ip_addr FROM article a
WHERE a.word = article.word
ORDER BY a.updated LIMIT 1) AS first_ip,
(SELECT a.ip_addr FROM article a
WHERE a.word = article.word
ORDER BY a.updated DESC LIMIT 1) AS last_ip
FROM notfound GROUP BY word;
Ответ 4
Предполагая, что вы хотите, чтобы идентификаторы записей с наименьшим low_price и самым высоким high_price вы могли добавить эти два столбца в ваш запрос,
SELECT
(SELECT id ORDER BY low_price ASC LIMIT 1) low_price_id,
(SELECT id ORDER BY high_price DESC LIMIT 1) high_price_id,
MIN(low_price), MAX(high_price), open, close
FROM symbols
WHERE date BETWEEN(.. ..)
GROUP BY YEARWEEK(date)
Если эффективность является проблемой, вы должны добавить столбец для "year_week", добавить некоторые индексы покрытия и разделить запрос на два.
Столбец 'year_week' - это только INT, установленный в значение YEARWEEK (дата) и обновляемый всякий раз, когда обновляется столбец "дата". Таким образом, вам не нужно пересчитывать его для каждого запроса, и вы можете его индексировать.
Новые индексы покрытия должны выглядеть так. Заказ имеет важное значение.
KEY yw_lp_id (year_week, low_price, id),
KEY yw_hp_id (year_week, high_price, id)
Затем вы должны использовать эти два запроса
SELECT
(SELECT id ORDER BY low_price ASC LIMIT 1) low_price_id,
MIN(low_price), open, close
FROM symbols
WHERE year_week BETWEEN(.. ..)
GROUP BY year_week
и
SELECT
(SELECT id ORDER BY high_price DESC LIMIT 1) high_price_id,
MAX(high_price), open, close
FROM symbols
WHERE year_week BETWEEN(.. ..)
GROUP BY year_week
Покрывающие индексы очень полезны. Для более подробной информации просмотрите этот.