Ho a che fare con una tabella Postgres (chiamata "lives") che contiene record con colonne per time_stamp, usr_id, transaction_id e lives_remaining. Ho bisogno di una query che mi dia il totale lives_remaining più recente per ogni usr_id
- Sono presenti più utenti (diversi usr_id)
- time_stamp non è un identificatore univoco: a volte gli eventi utente (uno per riga nella tabella) si verificano con lo stesso time_stamp.
- trans_id è unico solo per intervalli di tempo molto piccoli: nel tempo si ripete
- Le vite rimanenti (per un dato utente) possono sia aumentare che diminuire nel tempo
esempio:
time_stamp | lives_remaining | 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
Poiché avrò bisogno di accedere ad altre colonne della riga con i dati più recenti per ogni dato usr_id, ho bisogno di una query che dia un risultato come questo:
time_stamp | lives_remaining | usr_id | trans_id ----------------------------------------- 11:00 | 3 | 1 | 6 10:00 | 1 | 2 | 4 13:00 | 3 | 3 | 1
Come accennato, ogni usr_id può guadagnare o perdere vite e, a volte, questi eventi con data e ora si verificano così ravvicinati che hanno lo stesso timestamp! Pertanto questa query non funzionerà:
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
Invece, ho bisogno di utilizzare sia time_stamp (primo) che trans_id (secondo) per identificare la riga corretta. Devo anche quindi passare quelle informazioni dalla sottoquery alla query principale che fornirà i dati per le altre colonne delle righe appropriate. Questa è la query compromessa su cui sono riuscito a lavorare:
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
Ok, quindi funziona, ma non mi piace. Richiede una query all'interno di una query, un self join e mi sembra che potrebbe essere molto più semplice afferrando la riga che MAX ha trovato avere il timestamp e trans_id più grandi. La tabella "lives" ha decine di milioni di righe da analizzare, quindi vorrei che questa query fosse il più veloce ed efficiente possibile. Sono nuovo in RDBM e Postgres in particolare, quindi so che devo fare un uso efficace degli indici appropriati. Sono un po 'perso su come ottimizzare.
Ho trovato una discussione simile qui . Posso eseguire un tipo di Postgres equivalente a una funzione analitica Oracle?
Qualche consiglio sull'accesso alle informazioni sulle colonne correlate utilizzate da una funzione aggregata (come MAX), sulla creazione di indici e sulla creazione di query migliori sarebbe molto apprezzato!
PS È possibile utilizzare quanto segue per creare il mio caso di esempio:
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);