Мне нужна помощь в построении инструкции MySQL, где мне нужно найти предыдущие строки в одной таблице.
Мои данные выглядят так:
history_id (auto increment), object_id (существует несколько раз), timestamp,...
пример:
1, 2593, 2018-08-07 09:37:21
2, 2593, 2018-08-07 09:52:54
3, 15, 2018-08-07 10:41:15
4, 2593, 2018-08-07 09:57:36
Некоторые свойства этих данных:
Для каждой строки мне нужно найти самую предыдущую строку с тем же object_id.
Я нашел этот пост: https://dba.stackexchange.com/questions/24014/how-do-i-get-the-current-and-next-greater-value-in-one-select и работал с примерами, но Я не смог решить свою проблему.
Я просто проверил немного и дошел до этого момента:
SELECT
i1.history_id,
i1.object_id,
i1.timestamp AS state_time,
i2.timestamp AS previous_time
FROM
history AS i1
LEFT JOIN (
select timestamp as timestamp,history_id as history_id,object_id as object_id
from history
group by object_id
) AS i2 on i2.object_id = i1.object_id and i2.history_id < i1.history_id
Теперь мне нужно только отрезать подзапрос, что я получаю только самое высокое значение history_id для каждой строки, но не работает, когда я использую limit 1, потому что тогда я получу только одно значение.
У вас есть идея о том, как решить эту проблему? Или у вас могут быть лучшие и более эффективные методы?
Производительность здесь, потому что у меня 3,1 миллиона рядов, растущих выше..
Спасибо!
Лучшее направление - использовать функцию window
. Простой lag(timestamp)
бы работу с надлежащим порядком. См. Здесь: https://dev.mysql.com/doc/refman/8.0/en/window-function-descriptions.html#function_lag
Но если все, что вам нужно, это
вырезать подзапрос, что я получаю только самое высокое значение history_id для каждой строки, но не работает, когда я использую limit 1
Затем измените подзапрос из
select timestamp as timestamp,history_id as history_id,object_id as object_id
from history
group by object_id
в
select object_id as object_id, MAX(history_id) as history_id, MAX(timestamp) as timestamp
from history
group by object_id
В общем случае вы не должны ВЫБРАТЬ больше столбцов, чем у вас в предложении GROUP BY, если только они не включены в функцию агрегата.
lag
нет необходимости в подзапросе. Вы просто должны сделать SELECT history_id, object_id, timestamp as state_time, lag(timestamp) as prev_timefrom history WINDOW w AS (order by object_id, timestamp);
Но будьте осторожны, когда изменяется object_id, вы можете получить метку времени из предыдущего object_id. (не уверен, как MySQL справляется с этим). Затем Вы можете заменить lag(timestamp) as prev_time
на case when lag(object_id) != object_id then NULL else lag(timestamp) end as prev_time