time_stamp、usr_id、transaction_id、lives_remainingの列を持つレコードを含むPostgresテーブル(「lives」と呼ばれる)を扱っています。各usr_idの最新のlives_remaining合計を取得するクエリが必要です
- 複数のユーザーがいます(個別のusr_id)
- time_stampは一意の識別子ではありません。同じ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(最初)と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);