私は、time_stamp、usr_id、transaction_id、およびlives_remainingの列を持つレコードを含むPostgresテーブル( "lives"と呼ばれます)を処理しています。各usr_idの最新のlives_remaining合計を取得するクエリが必要です
- 複数のユーザーがいる(個別のusr_id)
- time_stampは一意の識別子ではありません。ユーザーのイベント(テーブルの行ごとに1つ)が同じtime_stampで発生することがあります。
- trans_idは、非常に狭い時間範囲でのみ一意です。時間の経過とともに繰り返します。
- remaining_lives(特定のユーザーの場合)は、時間の経過とともに増加および減少する可能性があります
例:
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
特定のusr_idごとに最新のデータが含まれる行の他の列にアクセスする必要があるため、次のような結果を返すクエリが必要です。
time_stamp | lives_remaining | 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(1番目)とtrans_id(2番目)の両方を使用する必要があります。次に、その情報をサブクエリからメインクエリに渡して、適切な行の他の列のデータを提供する必要もあります。これは、私が機能させたハッキングされたクエリです。
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を持っていることがわかった行を取得することで、はるかに簡単になるように思えます。テーブル「lives」には解析する数千万の行があるため、このクエリをできるだけ高速かつ効率的にしたいと思います。特にRDBMとPostgresは初めてなので、適切なインデックスを効果的に使用する必要があることはわかっています。最適化の方法について少し迷っています。
私はここで同様の議論を見つけました。Oracle分析関数と同等のタイプのPostgresを実行できますか?
集計関数(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);