2015-02-05 4 views
0

조인 테이블에서 GROUP BY를 수행하려고합니다. 나는 effective_at 주어진 user_id, foo_id의 쌍에 대한 최대 값 모든 레코드를 찾기 위해이 테이블을 조회하고 싶습니다최대 값을 포함하는 ID를 얻기 위해 비 ID 열로 Postgres 그룹을 수행하는 중 문제가 발생했습니다.

CREATE TABLE user_foos (
    id SERIAL PRIMARY KEY, 
    user_id INT NOT NULL, 
    foo_id INT NOT NULL, 
    effective_at DATETIME NOT NULL 
); 
ALTER TABLE user_foos 
    ADD CONSTRAINT user_foos_uniqueness 
    UNIQUE (user_id, foo_id, effective_at); 

: 같은 조인 테이블은 본질적으로 보인다. 나는 시도했다 다음 : 불행하게도, 이것은 오류가 발생

SELECT "user_foos"."id", 
     "user_foos"."user_id", 
     "user_foos"."foo_id", 
     max("user_foos"."effective_at") 
FROM "user_foos" 
GROUP BY "user_foos"."user_id", "user_foos"."foo_id"; 

:

나는 문제가 "ID"는 DB 집계 함수의 것을 사용하지에 관한 이해

column "user_foos.id" must appear in the GROUP BY clause or be used in an aggregate function

다른 ID를 가진 여러 레코드를 찾은 경우 수행 할 작업을 알지 못하지만이 열 (user_id, foo_ideffective_at)에서 내 기본 키로 인해 이런 일이 발생할 수 없다는 것을 알고 있습니다.

SELECT first_value("user_foos"."id") 
FROM "user_foos" 
GROUP BY "user_foos"."user_id", "user_foos"."foo_id" 
HAVING "user_foos"."effective_at" = max("user_foos"."effective_at") 

불행하게도,이 모두 다른 결과 :

SELECT first_value("user_foos"."id"), 
     "user_foos"."user_id", 
     "user_foos"."foo_id", 
     max("user_foos"."effective_at") 
FROM "user_foos" 
GROUP BY "user_foos"."user_id", "user_foos"."foo_id"; 

과 :

는이 문제를 해결하기 위해, 나는 또한 같은 idfirst_value window function를 사용하여 다른 변종의 숫자를 시도 오류 :

window function call requires an OVER clause

이상적으로, 제 목표는 모든 데이터를 가져 오는 것입니다. id과 일치하므로 하위 쿼리에서이 레코드를 일치시키기 위해이 테이블의 합법적 인 전체 행 데이터를 가져올 수 있습니다. 누구나 내가이 일을 어떻게 할 수 있는지에 대한 통찰력을 줄 수 있습니까?

답변

1

시도 :

SELECT * 
FROM (
    SELECT t.*, 
     row_number() OVER(partition by user_id, foo_id ORDER BY effective_at DESC) x 
    FROM user_foos t 
) 
WHERE x = 1 
0

당신은 당신이 ID의 하위 집합을 주문에 "조밀 한 순위"창 기능 필드를 만들 필요가 다음 세 가지 키의 합성을 기반으로 서브 쿼리를 사용하지 않으려면 , user_id 및 foo_id를 유효 날짜별로 정렬합니다. 그런 다음 하위 쿼리를 실행하고 rank_order = 1 인 레코드를 가져옵니다. 순위 순서는 발효 일로 결정되었으므로 각 foo와 사용자별로 가장 높은 발효 일을 기록의 모든 필드로 가져옵니다.

DATSET 
1 1 1 01/01/2001 
2 1 1 01/01/2002 
3 1 1 01/01/2003 
4 1 2 01/01/2001 
5 2 1 01/01/2001 

DATSET WITH RANK ORDER PARTITIONED BY FOO_ID, USER_ID ORDERED BY DATE DESC 
1 3 1 1 01/01/2001 
2 2 1 1 01/01/2002 
3 1 1 1 01/01/2003 
4 1 1 2 01/01/2001 
5 1 2 1 01/01/2001 

SELECT * FROM QUERY ABOVE WHERE RANK_ORDER=1 
3 1 1 1 01/01/2003 
4 1 1 2 01/01/2001 
5 1 2 1 01/01/2001 
+0

이것은 불행히도 웹 서버에서 레일스를 사용하여 궁극적으로 ORM을 통과하기 때문에 단일 쿼리로 제한해야합니다. 'QUERY ABOVE'를 참조하지 않고, 즉 단일 쿼리로이 작업을 수행하는 방법은 무엇입니까? –

+0

나는 그의 대답에서 kordirko가 그것을 철자했다고 생각합니다. –

3

포스트 그레스는 이러한 경우에 사용할 수 distinct on라는 아주 좋은 기능이 있습니다

SELECT DISTINCT ON (uf."user_id", uf."foo_id") uf.* 
FROM "user_foos" uf 
ORDER BY uf."user_id", uf."foo_id", uf."effective_at" DESC; 

그것은 괄호 안의 값에 따라, 그룹의 첫 번째 행을 반환합니다. order by 절에는 그룹의 첫 번째 행을 결정하는 세 번째 열뿐만 아니라이 값이 포함되어야합니다.

+0

이것은 정말 깨끗해 보입니다. 나는이 사진을 줄 것입니다. 고마워요! –

+0

@MattHuggins. . . 이것은 Postgres에 특화된 솔루션입니다 (그리고 구문은 향후 릴리스에서 성능이 저하 될 수도 있습니다). 그러나 종종 창 함수와 같은 다른 접근 방법보다 빠릅니다. –