문제

나는 몇 년 동안 (2003-2008) 고르지 않은 분산 데이터 (WRT 날짜)를 가지고 있습니다. 주어진 시작 및 종료 날짜 세트에 대한 데이터를 쿼리하여 지원되는 간격 (일, 주, 월, 분기, 연도)으로 데이터를 Gresql 8.3 (http://www.postgresql.org/docs/8.3/static/functions-datetime.html#functions-datetime-trunc).

문제는 일부 쿼리가 필요한 기간 동안 결과를 연속적으로 제공한다는 것입니다.

select to_char(date_trunc('month',date), 'YYYY-MM-DD'),count(distinct post_id) 
from some_table where category_id=1 and entity_id = 77  and entity2_id = 115 
and date <= '2008-12-06' and date >= '2007-12-01' group by 
date_trunc('month',date) order by date_trunc('month',date);
          to_char   | count 
        ------------+-------
         2007-12-01 |    64
         2008-01-01 |    31
         2008-02-01 |    14
         2008-03-01 |    21
         2008-04-01 |    28
         2008-05-01 |    44
         2008-06-01 |   100
         2008-07-01 |    72
         2008-08-01 |    91
         2008-09-01 |    92
         2008-10-01 |    79
         2008-11-01 |    65
        (12 rows)

그러나 그들 중 일부는 데이터가 없기 때문에 어떤 간격을 놓치고 있습니다.

select to_char(date_trunc('month',date), 'YYYY-MM-DD'),count(distinct post_id) 
from some_table where category_id=1 and entity_id = 75  and entity2_id = 115 
and date <= '2008-12-06' and date >= '2007-12-01' group by 
date_trunc('month',date) order by date_trunc('month',date);

        to_char   | count 
    ------------+-------

     2007-12-01 |     2
     2008-01-01 |     2
     2008-03-01 |     1
     2008-04-01 |     2
     2008-06-01 |     1
     2008-08-01 |     3
     2008-10-01 |     2
    (7 rows)

필요한 결과 집합이있는 경우 :

  to_char   | count 
------------+-------
 2007-12-01 |     2
 2008-01-01 |     2
 2008-02-01 |     0
 2008-03-01 |     1
 2008-04-01 |     2
 2008-05-01 |     0
 2008-06-01 |     1
 2008-07-01 |     0
 2008-08-01 |     3
 2008-09-01 |     0
 2008-10-01 |     2
 2008-11-01 |     0
(12 rows)

누락 된 항목의 경우 0의 카운트입니다.

나는 스택 오버플로에 대한 이전의 논의를 보았지만 내 그룹화 기간은 (일, 주, 월, 분기, 연도 중 하나이고 응용 프로그램에 의해 런타임을 결정했기 때문에 내 문제를 해결하지 못한다. 따라서 캘린더 테이블이나 시퀀스 테이블과 왼쪽 결합과 같은 접근 방식은 내가 추측하는 데 도움이되지 않습니다.

이에 대한 현재 솔루션은 캘린더 모듈을 사용하여 Turbogears 앱에서 이러한 틈을 메우는 것입니다.

이 작업을 수행하는 더 좋은 방법이 있습니까?

도움이 되었습니까?

해결책

작년 첫날 (예 :)의 목록을 만들 수 있습니다.

select distinct date_trunc('month', (current_date - offs)) as date 
from generate_series(0,365,28) as offs;
          date
------------------------
 2007-12-01 00:00:00+01
 2008-01-01 00:00:00+01
 2008-02-01 00:00:00+01
 2008-03-01 00:00:00+01
 2008-04-01 00:00:00+02
 2008-05-01 00:00:00+02
 2008-06-01 00:00:00+02
 2008-07-01 00:00:00+02
 2008-08-01 00:00:00+02
 2008-09-01 00:00:00+02
 2008-10-01 00:00:00+02
 2008-11-01 00:00:00+01
 2008-12-01 00:00:00+01

그런 다음 해당 시리즈에 참여할 수 있습니다.

다른 팁

이 질문은 오래되었습니다. 그러나 동료 사용자는 새로운 복제본의 마스터로 선택했기 때문에 적절한 답변을 추가하고 있습니다.

적절한 해결책

SELECT *
FROM  (
   SELECT day::date
   FROM   generate_series(timestamp '2007-12-01'
                        , timestamp '2008-12-01'
                        , interval  '1 month') day
   ) d
LEFT   JOIN (
   SELECT date_trunc('month', date_col)::date AS day
        , count(*) AS some_count
   FROM   tbl
   WHERE  date_col >= date '2007-12-01'
   AND    date_col <= date '2008-12-06'
-- AND    ... more conditions
   GROUP  BY 1
   ) t USING (day)
ORDER  BY day;
  • 사용 LEFT JOIN, 물론이야.

  • generate_series() 타임 스탬프 테이블을 즉시 생성 할 수 있으며 매우 빠릅니다.

  • 일반적으로 집계하는 것이 더 빠릅니다 ~ 전에 당신은 가입합니다. 최근 에이 관련 답변에서 sqlfiddle.com에 테스트 사례를 제공했습니다.

  • 캐스트 timestamp 에게 date (::date) 기본 형식의 경우. 더 많이 사용하십시오 to_char().

  • GROUP BY 1 첫 번째 출력 열을 참조하는 구문 속기입니다. 할 수 있습니다 GROUP BY day 또한 동일한 이름의 기존 열과 충돌 할 수 있습니다. 또는 GROUP BY date_trunc('month', date_col)::date 그러나 그것은 내 취향에 너무 길다.

  • 사용 가능한 간격 인수와 함께 작동합니다 date_trunc().

  • count() 결코 생산하지 않습니다 NULL (0 줄 없음) LEFT JOIN 하다.
    돌려 주다 0 대신에 NULL 외부에서 SELECT, 사용 COALESCE(some_count, 0) AS some_count. 매뉴얼.

  • a 보다 일반적인 솔루션 또는 임의의 시간 간격 이 밀접하게 관련된 답변을 고려하십시오.

런타임에 임시 테이블을 만들고 그에 가입 할 수 있습니다. 그것은 가장 의미가있는 것 같습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top