SQLITE: получить последнее обновление компонента для каждого отдельного компонента

#sql #sqlite #window-functions #partitioning

#sql #sqlite #окно-функции #разделение

Вопрос:

У меня есть простая база данных SQLITE, которая выглядит примерно так

 ID      TID      LASTUPDATE     UPDATE
============================================
1       213      2020-09-09         ok
2       416      2019-12-25         ok
3       213      2020-11-10         meh
...
999999  899      2020-12-11         bad
  

Существует около тысячи РАЗЛИЧНЫХ TID и сотни тысяч обновлений для каждого TID.

Я хотел бы получить последнее ОБНОВЛЕНИЕ для каждого отдельного идентификатора, независимо от того, когда оно было сделано, и я хотел бы сделать это за один раз. Я не хочу получать все отдельные идентификаторы, а затем для каждого идентификатора получать его ОБНОВЛЕНИЕ и LASTUPDATE

Что-то вроде «ВЫБРАТЬ * ИЗ ГРУППЫ обновлений ПО идентификатору» не будет работать, потому что GROUP BY выдаст первый найденный идентификатор, а мне нужен последний, который он сделал, поэтому я не хочу этого:

 1       213      2020-09-09         ok
2       416      2019-12-25         ok
...
  

Когда я хочу (по сути, порядок не имеет значения)

 3       213      2020-11-10         meh
2       416      2019-12-25         ok
...
  

К сожалению, мои знания SQL заканчиваются простыми грубыми материалами.

Любая помощь приветствуется.

(НА СЛЕДУЮЩИЙ ДЕНЬ)

В качестве обновления к этому — во всяком случае, для меня — основной способ получения всех отдельных идентификаторов, после чего foreach tid получит свое последнее обновление, был быстрее (.5s), когда число строк в таблице было ниже 200 000, как только оно превысило, что время выполнения взлетело на много секунд, и 3-й способ стал намного более быстрым.полезно, поскольку, хотя для запуска потребовалось 2,5 секунды, похоже, что это было постоянное время выполнения, которое, похоже, не сильно изменилось.

Также я не смог заставить работать 2-ю версию, но с некоторым редактированием

 select t.*
from updates t join
     (select id, tid, max(t.lastupdate) as max_lastupdate from updates t group by vid) tt
      on t.id = tt.id and (t.lastupdate = tt.max_lastupdate);
  

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

Итак, спасибо, Гордон Линофф, я ценю ваше время на это.

Ответ №1:

Один метод использует коррелированный подзапрос:

 select t.*
from t
where t.lastupdate = (select max(t2.lastupdate) from t t2 where t2.tid = t.tid);
  

Для повышения производительности требуется включить индекс (tid, lastupdate) .

Вы также можете попробовать сформулировать это как:

 select t.*
from t join
     (select tid, max(t2.lastupdate) as max_lastupdate
      from t
      group by tid
     ) tt
     on t.id = tt.id and t.lastupdate = tt.max_lastupdate;
  

Или:

 select t.*
from (select t.*, 
             row_number() over (partition by tid order by lastupdate desc) as seqnum
      from t
     ) t
where seqnum = 1;
  

Комментарии:

1. Не уверен, работает это или нет, запрос выполняется уже 40 минут! возможно, потребуется добавить еще несколько индексов!!!

2. хорошо, это работает, но даже при оптимизации для возврата результатов все равно требуется более 5 минут, что для моих нужд — обновления отображения графического интерфейса — не будет работать. Если я проделаю долгий путь, получу список различных tid, а затем получу максимальное значение lastupdate для каждого tid, которое по-прежнему медленное (.5 сек), но достаточно хорошее — спасибо, ты меня кое-чему научил.

3. @push22 . , , я добавил два других варианта. Я предложил соответствующий подзапрос, потому что думал, что это будет быстрее. Если вы хотите попробовать другие, мне было бы интересно, как они работают.

4. благодаря последнему обновлению время выполнения сократилось до 2,5 секунд! намного быстрее, но все равно быстрее долгий путь — но, эй, это то, что есть!