MySQL - получить предыдущую строку с тем же идентификатором

0

Мне нужна помощь в построении инструкции 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
  • комбинация object_id и timestamp всегда уникальна, дубликаты не возможны

Для каждой строки мне нужно найти самую предыдущую строку с тем же 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 миллиона рядов, растущих выше..

Спасибо!

Теги:
join
row
next
identifier

1 ответ

-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, если только они не включены в функцию агрегата.

  • 0
    Я также думал об этом (извините, я должен был это упомянуть), но тогда внутри подзапроса самое высокое значение выше, чем у строки, которая сравнивается с внешним запросом. Каким-то образом мне нужно сделать что-то в подзапросе, например: где history_id <i1.history_id. Но это приводит к ошибке SQL?
  • 0
    С функцией 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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню