Ich habe es mit einer Postgres-Tabelle ("Lives" genannt) zu tun, die Datensätze mit Spalten für time_stamp, usr_id, transaction_id und living_remaining enthält. Ich benötige eine Abfrage, die mir für jede usr_id die aktuellste Lebenssumme gibt
- Es gibt mehrere Benutzer (verschiedene usr_id's)
- time_stamp ist keine eindeutige Kennung: Manchmal treten Benutzerereignisse (zeilenweise in der Tabelle) mit demselben time_stamp auf.
- trans_id ist nur für sehr kleine Zeitbereiche eindeutig: Im Laufe der Zeit wiederholt es sich
- verbleibende Leben (für einen bestimmten Benutzer) können im Laufe der Zeit sowohl zunehmen als auch abnehmen
Beispiel:
Zeitstempel | Leben bleibt | 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
Da ich für jede angegebene usr_id auf andere Spalten der Zeile mit den neuesten Daten zugreifen muss, benötige ich eine Abfrage, die ein Ergebnis wie das folgende liefert:
Zeitstempel | Leben bleibt | usr_id | trans_id ----------------------------------------- 11:00 | 3 | 1 | 6 10:00 | 1 | 2 | 4 13:00 | 3 | 3 | 1
Wie bereits erwähnt, kann jede usr_id Leben gewinnen oder verlieren, und manchmal treten diese Ereignisse mit Zeitstempel so nahe beieinander auf, dass sie denselben Zeitstempel haben! Daher funktioniert diese Abfrage nicht:
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
Stattdessen muss ich sowohl time_stamp (erste) als auch trans_id (zweite) verwenden, um die richtige Zeile zu identifizieren. Ich muss diese Informationen dann auch von der Unterabfrage an die Hauptabfrage übergeben, die die Daten für die anderen Spalten der entsprechenden Zeilen bereitstellt. Dies ist die gehackte Abfrage, die ich zur Arbeit gebracht habe:
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
Okay, das funktioniert, aber ich mag es nicht. Es erfordert eine Abfrage innerhalb einer Abfrage, einen Self-Join, und es scheint mir, dass es viel einfacher sein könnte, wenn Sie die Zeile abrufen, die MAX mit dem größten Zeitstempel und der größten trans_id gefunden hat. Die Tabelle "lebt" enthält zig Millionen zu analysierende Zeilen. Daher möchte ich, dass diese Abfrage so schnell und effizient wie möglich ist. Ich bin insbesondere bei RDBM und Postgres neu, daher weiß ich, dass ich die richtigen Indizes effektiv nutzen muss. Ich bin ein bisschen verloren, wie man optimiert.
Ich habe hier eine ähnliche Diskussion gefunden . Kann ich eine Art von Postgres ausführen, die einer Oracle-Analysefunktion entspricht?
Alle Ratschläge zum Zugriff auf verwandte Spalteninformationen, die von einer Aggregatfunktion (wie MAX) verwendet werden, zum Erstellen von Indizes und zum Erstellen besserer Abfragen sind sehr willkommen!
PS Sie können Folgendes verwenden, um meinen Beispielfall zu erstellen:
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);