Я имею дело с таблицей Postgres (называемой "жизнями"), которая содержит записи со столбцами для time_stamp, usr_id, transaction_id и life_remaining. Мне нужен запрос, который предоставит мне самое последнее количество жизней_ремайн для каждого usr_id
- Есть несколько пользователей (разные usr_id)
- time_stamp не является уникальным идентификатором: иногда пользовательские события (по одному в таблице) будут происходить с одной и той же time_stamp.
- trans_id уникален только для очень малых временных диапазонов: со временем он повторяется
- оставшееся_жизнь (для данного пользователя) может как увеличиваться, так и уменьшаться с течением времени
пример:
отметка_времени | жизнь_ремонта | usr_id | trans_id ----------------------------------------- 07:00 | 1 | 1 | 1 09:00 | 4 | 2 | 2 10:00 | 2 | 3 | 3 10:00 | 1 | 2 | 4 11:00 | 4 | 1 | 5 11:00 | 3 | 1 | 6 13:00 | 3 | 3 | 1
Поскольку мне нужно будет получить доступ к другим столбцам строки с последними данными для каждого заданного usr_id, мне нужен запрос, который дает такой результат:
отметка_времени | жизнь_ремонта | usr_id | trans_id ----------------------------------------- 11:00 | 3 | 1 | 6 10:00 | 1 | 2 | 4 13:00 | 3 | 3 | 1
Как уже упоминалось, каждый usr_id может приносить или терять жизни, и иногда эти события с отметкой времени происходят так близко друг к другу, что имеют одинаковую отметку времени! Следовательно, этот запрос не будет работать:
SELECT b.time_stamp,b.lives_remaining,b.usr_id,b.trans_id FROM
(SELECT usr_id, max(time_stamp) AS max_timestamp
FROM lives GROUP BY usr_id ORDER BY usr_id) a
JOIN lives b ON a.max_timestamp = b.time_stamp
Вместо этого мне нужно использовать time_stamp (first) и trans_id (second), чтобы идентифицировать правильную строку. Затем мне также нужно передать эту информацию из подзапроса в основной запрос, который предоставит данные для других столбцов соответствующих строк. Это взломанный запрос, с которым мне пришлось работать:
SELECT b.time_stamp,b.lives_remaining,b.usr_id,b.trans_id FROM
(SELECT usr_id, max(time_stamp || '*' || trans_id)
AS max_timestamp_transid
FROM lives GROUP BY usr_id ORDER BY usr_id) a
JOIN lives b ON a.max_timestamp_transid = b.time_stamp || '*' || b.trans_id
ORDER BY b.usr_id
Хорошо, это работает, но мне это не нравится. Для этого требуется запрос внутри запроса, самосоединение, и мне кажется, что это может быть намного проще, если взять строку, которая, как обнаружил MAX, имеет наибольшую временную метку и trans_id. Таблица "живет" содержит десятки миллионов строк для анализа, поэтому мне хотелось бы, чтобы этот запрос был как можно более быстрым и эффективным. Я новичок в RDBM и Postgres в частности, поэтому знаю, что мне нужно эффективно использовать правильные индексы. Я немного не понимаю, как оптимизировать.
Я нашел подобное обсуждение здесь . Могу ли я выполнить какой-либо тип Postgres, эквивалентный аналитической функции Oracle?
Мы будем очень благодарны за любые советы по доступу к связанной информации столбцов, используемой агрегатной функцией (например, MAX), созданию индексов и созданию более качественных запросов!
PS Для создания моего примера вы можете использовать следующее:
create TABLE lives (time_stamp timestamp, lives_remaining integer,
usr_id integer, trans_id integer);
insert into lives values ('2000-01-01 07:00', 1, 1, 1);
insert into lives values ('2000-01-01 09:00', 4, 2, 2);
insert into lives values ('2000-01-01 10:00', 2, 3, 3);
insert into lives values ('2000-01-01 10:00', 1, 2, 4);
insert into lives values ('2000-01-01 11:00', 4, 1, 5);
insert into lives values ('2000-01-01 11:00', 3, 1, 6);
insert into lives values ('2000-01-01 13:00', 3, 3, 1);