Saya berurusan dengan tabel Postgres (disebut "kehidupan") yang berisi catatan dengan kolom untuk time_stamp, usr_id, transaction_id, dan life_remaining. Saya butuh kueri yang akan memberi saya total sisa_hidup terbaru untuk setiap usr_id
- Ada beberapa pengguna (usr_id berbeda)
- time_stamp bukanlah pengenal unik: terkadang peristiwa pengguna (satu per baris dalam tabel) akan terjadi dengan time_stamp yang sama.
- trans_id unik hanya untuk rentang waktu yang sangat kecil: berulang kali
- sisa_hidup (untuk pengguna tertentu) dapat meningkat dan menurun seiring waktu
contoh:
time_stamp | Lifes_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
Karena saya perlu mengakses kolom lain dari baris dengan data terbaru untuk setiap usr_id yang diberikan, saya memerlukan kueri yang memberikan hasil seperti ini:
time_stamp | Lifes_remaining | usr_id | trans_id ----------------------------------------- 11:00 | 3 | 1 | 6 10:00 | 1 | 2 | 4 13:00 | 3 | 3 | 1
Seperti yang disebutkan, setiap usr_id bisa mendapatkan atau kehilangan nyawa, dan terkadang peristiwa dengan stempel waktu ini terjadi sangat berdekatan sehingga memiliki stempel waktu yang sama! Oleh karena itu, kueri ini tidak akan berfungsi:
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
Sebagai gantinya, saya perlu menggunakan time_stamp (first) dan trans_id (second) untuk mengidentifikasi baris yang benar. Saya juga perlu meneruskan informasi itu dari subkueri ke kueri utama yang akan menyediakan data untuk kolom lain dari baris yang sesuai. Ini adalah kueri yang diretas sehingga saya berhasil:
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
Oke, jadi ini berhasil, tapi saya tidak menyukainya. Ini membutuhkan kueri dalam kueri, bergabung sendiri, dan menurut saya itu bisa jauh lebih sederhana dengan mengambil baris yang menurut MAX memiliki cap waktu dan trans_id terbesar. Tabel "hidup" memiliki puluhan juta baris untuk diurai, jadi saya ingin kueri ini secepat dan seefisien mungkin. Saya baru mengenal RDBM dan Postgres pada khususnya, jadi saya tahu bahwa saya perlu menggunakan indeks yang tepat secara efektif. Saya agak bingung tentang cara mengoptimalkan.
Saya menemukan diskusi serupa di sini . Dapatkah saya melakukan beberapa jenis Postgres yang setara dengan fungsi analitik Oracle?
Saran apa pun tentang mengakses informasi kolom terkait yang digunakan oleh fungsi agregat (seperti MAX), membuat indeks, dan membuat kueri yang lebih baik akan sangat dihargai!
PS Anda dapat menggunakan berikut ini untuk membuat kasus contoh saya:
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);