Я маю справу з таблицею Postgres (яка називається "життя"), яка містить записи зі стовпцями для time_stamp, usr_id, transaction_id та lives_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 (перший), і trans_id (другий), щоб визначити правильний рядок. Потім мені також потрібно передати цю інформацію з підзапиту до основного запиту, який буде надавати дані для інших стовпців відповідних рядків. Це хакерський запит, який я приступив до роботи:
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);