我正在处理一个Postgres表(称为“ lives”),该表包含带有time_stamp,usr_id,transaction_id和live_remaining列的记录。我需要一个查询,该查询将为我提供每个usr_id的最新live_remaining总数
- 有多个用户(与usr_id不同)
- time_stamp不是唯一的标识符:有时,用户事件(表中的每一行)将使用相同的time_stamp发生。
- trans_id仅在很小的时间范围内才是唯一的:随着时间的流逝,它会重复
- (对于给定的用户)剩余的生存时间可以随着时间增加和减少
例:
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(第二)来标识正确的行。然后,我还需要将该信息从子查询传递到主查询,该主查询将提供相应行的其他列的数据。这是我必须使用的修改查询:
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);