2016-08-05 2 views
0

나는이 포함 된 테이블이 positions 다음과 같이이 테이블은 다음과 같습니다단일 결과는

user_id | current | started_at | finished_at 
2  | false | 10-07-2016 | 02-08-2016 
1  | false | 19-07-2016 | 27-07-2016 
1  | true | 29-07-2016 | null 
3  | true | 20-07-2016 | null 
3  | false | 01-07-2016 | 18-07-2016 

나는에 따라 중 하나 started_at 또는 finished_at 날짜를 사용하는 경우를 사용하여이 테이블을 정렬하고 있습니다를 current 여부를 true 또는 false입니다

SELECT * 
FROM positions 
ORDER BY 
    CASE 
     WHEN current = true 
      THEN started_at 
     ELSE finished_at 
    END 
DESC 

이 예상대로 잘 작동하지만 지금은 각 user_id

0 첫 번째 행을 추출 할

내 예제 데이터에서 다음과 같이 반환하고 싶습니다. 나는이 생각

user_id | current | started_at | finished_at 
2  | false | 10-07-2016 | 02-08-2016 
1  | true | 29-07-2016 | null 
3  | true | 20-07-2016 | null 

GROUP BY와 함께 할 수 있지만, 나는 그것이 오류없이 작동하거나 어쩌면 내가 잘 모르겠어요, 하위 쿼리를 필요로 얻을 수 없습니다. 원하는 결과를 쉽게 당신이 표준이 아닌 PostgreSQL을 DISTINCT ON 기능을 사용하여 원하는 것을 얻을 수 있습니다 user_id 1.

에 대한 행을 표시하기 때문에

+0

"첫 번째 행만"은 "WHERE current = true"와 같습니까? – Razzka

+0

죄송합니다. 실수로 수정했습니다. – Rob

답변

2

이것은 창 기능을 사용할 수있는 좋은 기회입니다.

SELECT user_id, current, started_at, finished_at, 
    row_number() OVER (PARTITION BY user_id) AS row_number 
    FROM positions 
    ORDER BY CASE WHEN current = true 
     THEN started_at ELSE finished_at END DESC 

이것은 윈도우 함수에서 오는 새 열 "ROW_NUMBER"당신에게 원래의 테이블을 줄 것이다 : 당신은 다음과 같습니다 쿼리를 작성하는 윈도우 기능을 사용할 수 있습니다. 사용자가 row_number를 가져 오기 때문에 user_id로 분할합니다. 제공 한 ORDER 절을 사용하십시오. 이 문을 하위 쿼리로 사용하려면 전체 응답을 얻으려면 WHERE 절을 사용하여 row_number = 1 만 선택하고 필요한 모든 필드를 가져옵니다. WHERE 절에서 창 함수를 사용할 수 없기 때문에 하위 쿼리가 필요합니다.

SELECT user_id, current, started_at, finished_at 
FROM 
(
SELECT user_id, current, started_at, finished_at, 
    row_number() OVER (PARTITION BY user_id) AS row_number 
FROM positions 
ORDER BY CASE WHEN current = true 
    THEN started_at ELSE finished_at END DESC 
) pos 
WHERE row_number= 1 
+0

또한 - 창 함수를 처음 사용하는 경우 PostgreSQL의 유용한 설명서가 있습니다 : [창 함수] (https://www.postgresql.org/docs/9.1/static/tutorial-window.html) – MattPerry

+0

도움 주셔서 감사합니다 , 나는 그 접근법을 좋아한다. 불행히도 그것은 내게 예상 된 결과를주지 않습니다. 결과는 날짜 열별로 정렬되지 않습니다. 그것은 주문에 의해 user_id http://pastebin.com/r5LkYXGC – Rob

+0

당신이 무슨 뜻인지 알 겠어. 파티션 외부에서 정렬을 풀기 위해 답을 편집하고 rank() 대신 row_number() 함수를 사용했습니다. 순위는 동일한 user_id에 대해 정확히 동일한 날짜가있는 경우 "1"값을 복제합니다.전체 데이터 세트에 포함 시킬지는 모르겠지만 더 안전합니다. – MattPerry

0

나는, 당신이 당신의 예에서 실수를 한 것 같아요 :

SELECT DISTINCT ON (user_id) * FROM 
    (SELECT * FROM positions 
    ORDER BY 
     CASE 
      WHEN current = true 
      THEN started_at 
      ELSE finished_at 
     END 
    DESC) q; 

이렇게하면 각 user_id의 첫 번째 행을 제외하고 모두 제거됩니다.

+0

예문의 예상 결과가 정확한 날짜로 정렬 된 첫 번째 행입니다. 불행히도 당신의 답은 "SELECT DISTINCT ON 식은 초기 ORDER BY 식과 일치해야합니다." – Rob

+0

정말로 죄송합니다. 나는 대답을 편집했다. –

+0

도움을 주셔서 감사합니다. @ laurenz-albe 불행히도 내부 선택 만 정렬되므로 결과 데이터 집합은 케이스에 사용 된 날짜별로 정렬되지 않습니다. 이제 매트의 작업 버전이 있습니다. 귀하의 의견을 보내 주셔서 감사합니다! – Rob