У меня есть система управления документами, которая записывает все исторические события в таблицу истории. Мне было предложено предоставить старейший doc_id, который имеет статус 5 для данного клиента на определенную дату. Таблица выглядит примерно так (усеченный для простоты):PostgreSQL - поиск самой старой записи с определенным значением
doc_history:
id integer
doc_id integer
event_date timestamp
client_id integer
status_id integer
В client_id и status_id столбцы значение документа после того, как событие произошло. Это означает, что максимальная строка события истории для документа, определенного doc_id, будет соответствовать тем же столбцам в таблице документов. Ограничивая события определенной датой события, вы можете видеть, какие значения документа были в то время. Поскольку эти значения не являются статическими, я не могу просто просто искать конкретный client_id с status_id из 5, потому что найденный результат может не соответствовать максимальному (id) документа. Надеюсь, это имеет смысл.
То, что я нашел, чтобы работать, но медленно, заключается в следующем:
select
t.*
from
(select
distinct on (doc_id),
*
from
doc_history
where
event_date <= '2013-02-17 23:59:59'
order by
doc_id, id desc) t
where
t.client_id = 9999 and
t.status_id = 5
limit 1;
В принципе, я получаю максимальный идентификатор для конкретного документа ID до заданной максимальной даты события, а затем что этот максимальный элемент истории присвоен данному клиенту со статусом, установленным на 5.
Недостатком этого является то, что я просматриваю все записи истории для всех клиентов, чтобы получить их максимальные значения, а затем найти то, что я ищу для одного клиента и статус. На данный момент это сканирует примерно 15,06 миллионов строк и занимает около 90 секунд на моем dev-сервере (который не пылает быстро).
Чтобы усложнить ситуацию, мне нужно сделать это за каждый день предыдущей недели или семь раз за каждый прогон. Кроме того, все документы в системе начинаются со статуса 5, который представляет новый. Это делает его так, чтобы этот запрос просто возвращает первый документ, введенный для этого клиента:
select * from doc_history where client_id = 9999 and
status_id = 5 and
event_date <= '2013-02-17 23:59:59'
order by id limit 1;
То, что я надеюсь сделать это сканирование, пока я не найду максимальную запись истории для конкретного документа, который соответствует конкретному клиенту и значения статуса без необходимости сначала находить максимальные идентификаторы для всех идентификаторов документов для всех клиентов. Я не знаю, можно ли это сделать с помощью функции окон (разделение) или некоторой другой логики, которую я сейчас не вижу.
Пример одного из событий в doc_history таблице:
# select id, doc_id, event, old_value, new_value, event_date, client_id, status_id from doc_history where doc_id = 9999999 order by id;
id | doc_id | event | old_value | new_value | event_date | client_id | status_id
----------+---------+-------+-----------+-----------+----------------------------+-----------+-----------
25362415 | 9999999 | 13 | | | 2013-02-14 11:49:50.032824 | 9999 | 5
25428192 | 9999999 | 15 | | | 2013-02-18 11:15:48.272542 | 9999 | 5
25428193 | 9999999 | 7 | 5 | 1 | 2013-02-18 11:15:48.301377 | 9999 | 1
событий 7 статус изменился, и старые и новые значения показывают, что оно было изменено с 5 до 1, что находит свое отражение в status_id. Для event_date меньше или равно 2013-02-17 23:59:59, вышеуказанная запись была бы самым старым «NEW» документом со статусом_ид 5, но после 2/17/2013 этого не было бы.
Что я буду за это : что является самым старым необработанным (NEW) документом для клиента X 2/17/2013. Если я получу старое событие из таблицы истории, я получу новый документ, но мне нужно новое событие до 2/17/2013 со статусом 5 (новый) для клиента X. Значения состояния и клиента не являются static между событиями, потому что они отражают изменения, вызванные событиями (например, изменение статуса и клиента). – Adam
Я добавил пример того, как выглядят строки в таблице. – Adam