Это не совсем то, что вы просили, но следующий пример довольно близок ....
Пример 1:
select
floor(timestampdiff(SECOND, tbl.time, most_recent.time)/604800) as period_index,
unix_timestamp(max(tbl.time)) as period_timestamp
from
tbl
, (select max(time) as time from tbl) most_recent
group by period_index
дает результаты:
+--------------+------------------+
| period_index | period_timestamp |
+--------------+------------------+
| 0 | 1317183002 |
| 1 | 1316571974 |
| 2 | 1315967707 |
+--------------+------------------+
Это разбивает набор данных на группы на основе «периодов», где (в этом примере) каждый период составляет 7 дней (604800 секунд).period_timestamp
, которое возвращается для каждого периода, является «самой последней» (самой последней) отметкой времени, которая попадает в этот период.
Все границы периода вычисляются на основе самой последней временной отметки в базе данных, а не вычисляются время начала и окончания каждого периода индивидуально на основе временной отметки периода перед ним.Разница невелика - ваш вопрос требует последнего (итеративный подход), но я надеюсь, что первый (подход, который я описал здесь) будет достаточным для ваших нужд, поскольку SQL плохо подходит для реализации итерационных алгоритмов.
Если вам действительно нужно определять каждый период на основе отметки времени в предыдущем периоде, тогда лучшим вариантом будет итеративный подход - либо с использованием языка программирования по вашему выбору (например,php), или путем создания хранимой процедуры, которая использует курсор.
Edit # 1
Вот структура таблицы для приведенного выше примера.
CREATE TABLE `tbl` (
`id` int(10) unsigned NOT NULL auto_increment PRIMARY KEY,
`time` datetime NOT NULL
)
Edit # 2
Хорошо, сначала: я улучшил исходный пример запроса (см. Исправленный «Пример 1» выше).Он по-прежнему работает так же и дает те же результаты, но он чище, эффективнее и проще для понимания.
Теперь ... приведенный выше запрос является групповым запросом, то есть он показывает агрегированные результаты.для групп «период», как я описал выше, а не построчно, как «обычный» запрос.При групповом запросе вы ограничены использованием только агрегированных столбцов.Агрегированные столбцы - это те столбцы, которые названы в предложении group by
или вычисляются с помощью агрегатной функции, например MAX(time)
).Невозможно извлечь значимые значения для неагрегированных столбцов (например, id
) из проекции группового запроса.
К сожалению, mysql не выдает ошибку при попытке сделатьэтот.Вместо этого он просто выбирает случайное значение из сгруппированных строк и показывает это значение для неагрегированного столбца в сгруппированном результате.Это то, что вызывает странное поведение, о котором ОП сообщало при попытке использовать код из Примера №1.
К счастью, эту проблему довольно легко решить.Просто оберните другой запрос вокруг группового запроса, чтобы выбрать интересующую вас строку за строкой ...
Пример 2:
SELECT
entries.id,
entries.time,
periods.idx as period_index,
unix_timestamp(periods.time) as period_timestamp
FROM
tbl entries
JOIN
(select
floor(timestampdiff( SECOND, tbl.time, most_recent.time)/31536000) as idx,
max(tbl.time) as time
from
tbl
, (select max(time) as time from tbl) most_recent
group by idx
) periods
ON entries.time = periods.time
Результат:
+-----+---------------------+--------------+------------------+
| id | time | period_index | period_timestamp |
+-----+---------------------+--------------+------------------+
| 598 | 2011-09-28 04:10:02 | 0 | 1317183002 |
| 996 | 2010-09-27 22:57:05 | 1 | 1285628225 |
+-----+---------------------+--------------+------------------+
Примечания:
В примере 2 используется длина периода 31536000 seconds
(365 дней).В то время как в Примере 1 (выше) используется период 604800 seconds
(7 дней).Кроме этого, внутренний запрос в Примере 2 такой же, как и основной запрос, показанный в Примере 1.
Если совпадающий период_трица принадлежит более чем одной записи (т. Е. Двум или более записямимеют точно такое же время, и это время соответствует одному из выбранных значений period_time), тогда вышеупомянутый запрос (Пример 2) будет включать несколько строк для данной временной метки периода (по одной для каждого соответствия).Какой бы код ни потреблял этот набор результатов, он должен быть подготовлен для обработки такого крайнего случая.
Стоит также отметить, что эти запросы будут работать намного, намного лучше, если вы определите индекс для столбца datetime.,Для моего примера схемы это будет выглядеть так:
ALTER TABLE tbl ADD INDEX idx_time ( time )