J'ai affaire à une table Postgres (appelée "lives") qui contient des enregistrements avec des colonnes pour time_stamp, usr_id, transaction_id et lives_remaining. J'ai besoin d'une requête qui me donnera le total de lives_remaining le plus récent pour chaque usr_id
- Il y a plusieurs utilisateurs (usr_id distincts)
- time_stamp n'est pas un identifiant unique: parfois les événements utilisateur (un par ligne dans la table) se produiront avec le même time_stamp.
- trans_id n'est unique que pour de très petites plages de temps: avec le temps, il se répète
- left_lives (pour un utilisateur donné) peut à la fois augmenter et diminuer avec le temps
exemple:
horodatage | lives_remaining | usr_id | trans_id ----------------------------------------- 07h00 | 1 | 1 | 1 09h00 | 4 | 2 | 2 10:00 | 2 | 3 | 3 10:00 | 1 | 2 | 4 11h00 | 4 | 1 | 5 11h00 | 3 | 1 | 6 13h00 | 3 | 3 | 1
Comme je devrai accéder aux autres colonnes de la ligne avec les dernières données pour chaque usr_id donné, j'ai besoin d'une requête qui donne un résultat comme celui-ci:
horodatage | lives_remaining | usr_id | trans_id ----------------------------------------- 11h00 | 3 | 1 | 6 10:00 | 1 | 2 | 4 13h00 | 3 | 3 | 1
Comme mentionné, chaque usr_id peut gagner ou perdre des vies, et parfois ces événements horodatés se produisent si près les uns des autres qu'ils ont le même horodatage! Par conséquent, cette requête ne fonctionnera pas:
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
Au lieu de cela, je dois utiliser à la fois time_stamp (premier) et trans_id (deuxième) pour identifier la ligne correcte. Je dois également ensuite transmettre ces informations de la sous-requête à la requête principale qui fournira les données pour les autres colonnes des lignes appropriées. Voici la requête piratée que j'ai obtenue:
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
D'accord, ça marche, mais je n'aime pas ça. Cela nécessite une requête dans une requête, une auto-jointure, et il me semble que cela pourrait être beaucoup plus simple en saisissant la ligne que MAX a trouvé comme ayant le plus grand horodatage et trans_id. La table "lives" a des dizaines de millions de lignes à analyser, donc j'aimerais que cette requête soit aussi rapide et efficace que possible. Je suis nouveau dans RDBM et Postgres en particulier, donc je sais que je dois utiliser efficacement les bons index. Je ne sais pas trop comment optimiser.
J'ai trouvé une discussion similaire ici . Puis-je effectuer un type de Postgres équivalent à une fonction analytique Oracle?
Tout conseil sur l'accès aux informations de colonne associées utilisées par une fonction d'agrégation (comme MAX), la création d'index et la création de meilleures requêtes serait très apprécié!
PS Vous pouvez utiliser ce qui suit pour créer mon exemple de cas:
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);