2012-09-03 3 views
1

흥미로운 문제를 해결하려고합니다.고유 값 선택 날짜별로 정렬

n_place_id dt_visit_date 
(integer) (date) 
========== ============= 
    1   10/02/2012 
    3   11/03/2012 
    4   11/05/2012 
    13   14/06/2012 
    3   04/10/2012 
    3   03/11/2012 
    5   05/09/2012 
    13   18/08/2012 

기본적으로, 각 장소를 방문 할 수 있습니다 여러 번 - 그리고 - 나는,이 컬럼 (일/월/년을이 샘플의 날짜가 유럽 형식으로 표시되는) 다른 데이터 중,이 테이블이 날짜는 과거 (완료된 방문) 또는 미래 (계획된 방문) 일 수 있습니다. 편의상, 오늘 방문은 계획된 미래 방문의 일부입니다.

  1. 미래 방문은 지난 방문
  2. 을하기 전에 이동 :

    지금, 나는 다음과 같은 순서로 정렬 (날짜 없음)이 표에서 독특한 장소 ID를 당길 것이 테이블에 선택을 실행해야

  3. 미래 방문은 미래의 방문을 같은 장소
  4. 에 대한 방문을지나 이상의 분류에 우선, 가장 빠른 날짜가 지난 방문을 같은 장소
  5. 에 대한 분류에 우선해야하며, 최신 날짜가 탁합니다 동일한 장소에 대한 정렬에서의 우선 순위. 샘플 데이터가 위 대한

예를 들어, I 필요한 결과는 다음 지금

5  (earliest future visit) 
3  (next future visit into the future) 
13  (latest past visit) 
4  (previous past visit) 
1  (earlier visit in the past) 

, I 원하는 정도로 같은 order bycase when를 사용하여 정렬 얻을 수

select 
    n_place_id 
from 
    place_visit 
order by 
    (case when dt_visit_date >= now()::date then 1 else 2 end), 
    (case when dt_visit_date >= now():: date then 1 else -1 end) * extract(epoch from dt_visit_date) 

일종의이 필요하지만 반복되는 ID는 포함되지만 고유 한 장소 ID가 필요합니다. select 문에 distinct을 추가하려고하면 postgres가 select 절에 order by이 있어야한다고 불평합니다. 그렇지만 더 이상 고유하지는 않습니다. 거기에 날짜가 있으므로 더 이상 의미가 없습니다.

어떻게 든 나는 하나의 선택 진술에서 필요한 결과를 얻는 방법이 있어야한다고 생각하지만, 그것을 수행하는 방법을 고민 할 수는 없다.

이 작업을 수행 할 수 없다면 코드에서 모든 작업을 수행해야하지만 한 SQL 문에서이 작업을 수행하는 것이 좋습니다.

P. 정렬 할 데이터 집합이 크지 않기 때문에 성능에 대해 걱정하지 않습니다. where 절이 적용된 후에는 약 10 개 이상의 레코드가 거의 포함되지 않습니다.

답변

1

DISTINCT ON은이

select n_place_id 
from 
(
    select *, 
    extract(epoch from (dt_visit_date - now())) as seconds, 
    1 - SIGN(extract(epoch from (dt_visit_date - now()))) as futurepast 
    from #t 
) v 
group by n_place_id 
order by max(futurepast) desc, min(abs(seconds)) 
+0

내가 라인에'캐스트 integer'하는 간격을 캐스팅 할 수 없습니다 '오류 ((dt_visit_date를 - 지금()) int로서) days' –

+0

로 – podiluska

+0

네 위의 편집을보십시오! 이것은 그것에 관한 것입니다. 그냥'SIGN (...)'을''1-SIGN (...) ''로 바꿔야 만했다. 많은 감사합니다! –

2

을 시도하면 쉽게 결과 n_place_id과 행의 추가 열을 표시 할 수 있습니다 :

SELECT n_place_id, dt_visit_date 
FROM (
    SELECT DISTINCT ON (n_place_id) * 
     ,dt_visit_date < now()::date AS prio -- future first 
     ,@(now()::date - dt_visit_date) AS diff -- closest first 
    FROM place_visit 
    ORDER BY n_place_id, prio, diff 
    ) x 
ORDER BY prio, diff; 

효과적으로 내가 (를 포함하여 최초의 미래의 날짜가있는 행을 선택 "오늘 ") n_place_id - 또는 최신 날짜가 과거에 실패했습니다.
그런 다음 결과 행은 동일한 기준으로 정렬됩니다. "absolute value" @이 관련 답변에서 "가장 가까운 첫번째"는 포스트 그레스에
  • 보다 구체적인 DISTINCT ON를 정렬하는 데 도움이 TRUE
  • 전에

    • FALSE 종류.

    결과 :

    n_place_id | dt_visit_date 
    ------------+-------------- 
    5   | 2012-09-05 
    3   | 2012-10-04 
    13   | 2012-08-18 
    4   | 2012-05-11 
    1   | 2012-02-10