time_stamp, usr_id, transaction_id 및 lives_remaining에 대한 열이있는 레코드가 포함 된 Postgres 테이블 ( "lives"라고 함)을 다루고 있습니다. 각 usr_id에 대한 가장 최근의 lives_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 | 삼 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)에서 사용하는 관련 열 정보에 액세스하고, 인덱스를 만들고, 더 나은 쿼리를 만드는 방법에 대한 조언을 주시면 감사하겠습니다!
추신 다음을 사용하여 예제 케이스를 만들 수 있습니다.
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);