Postgres- 누락 된 데이터에 대해 0 카운트로 행을 반환하는 방법은 무엇입니까?
-
19-08-2019 - |
문제
나는 몇 년 동안 (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 보다 일반적인 솔루션 또는 임의의 시간 간격 이 밀접하게 관련된 답변을 고려하십시오.
런타임에 임시 테이블을 만들고 그에 가입 할 수 있습니다. 그것은 가장 의미가있는 것 같습니다.