1

주어진 타임 스탬프와 타임 스탬프의 집계 값을 가져 오는 쿼리를 만드는 데 어려움이 있습니다. 주어진 다음의 스키마는 :데이터에 따라 오늘과 전날의 집계

인해 데이터 격차에 ts 열에서 차이가있다
name TEXT, 
ts TIMESTAMP, 
X NUMERIC, 
Y NUMERIC 

, 나는 첫 번째 절반은 간단

name, 
date_trunc('day' q1.ts), 
avg(q1.X), 
sum(q2.Y), 
date_trunc('day', q2.ts), 
avg(q2.X), 
sum(q2.Y) 

생산하는 쿼리를 구축하기 위해 노력하고있어 :

SELECT q1.name, date_trunc('day', q1.ts), avg(q1.X), sum(q1.Y) 
FROM data as q1 
GROUP BY 1, 2 
ORDER BY 1, 2; 

그러나 관계를 생성하여 각 행에 대해 이전에 "일"을 찾는 방법을 모르십니까? 나는 내부는 다음과 같이 가입 해결하려고 노력 해요 :

SELECT q1.name, q1.day, q1.avg, q1.sum, q2.day, q2.avg, q2.sum 
FROM (
    SELECT name, date_trunc('day', ts) AS day, avg(X) AS avg, sum(Y) as sum 
    FROM data 
    GROUP BY 1,2 
    ORDER BY 1,2 
) q1 INNER JOIN (
    SELECT name, date_trunc('day', ts) AS day, avg(X) AS avg, sum(Y) as sum 
    FROM data 
    GROUP BY 1,2 
    ORDER BY 1,2 
) q2 ON (
    q1.name = q2.name 
    AND q2.day = q1.day - interval '1 day' 
); 

다음 "날"현재 전날보다 1 일입니다 때, 그것은 경우에는 적용되지 않습니다되는이의 문제.

답변

2

여기서 특별한 어려움은 일 후에 행을 집계해야합니다. 창이 기능이 적용될 때 창 함수가 row_number() 인 단일 쿼리 수준에서 GROUP BY 번으로 집계 후에이 작업을 수행 할 수 있습니다. "일"을 얻을 수

WITH q AS (
    SELECT name, ts::date AS day 
      ,avg(x) AS avg_x, sum(y) AS sum_y 
      ,row_number() OVER (PARTITION BY name ORDER BY ts::date) AS rn 
    FROM data 
    GROUP BY 1,2 
    ) 
SELECT q1.name, q1.day, q1.avg_x, q1.sum_y 
     ,q2.day AS day2, q2.avg_x AS avg_x2, q2.sum_y AS sum_y2 
FROM q  q1 
LEFT JOIN q q2 ON q1.name = q2.name 
       AND q1.rn = q2.rn + 1 
ORDER BY 1,2; 

일 (ts::date)에 간단한 캐스트를 사용하는 대신 date_trunc('day', ts)의 : 또한

는 같은 하위 쿼리를 여러 번 실행 방지하기 위해 CTE를 사용합니다.
LEFT [OUTER] JOIN (반대로 [INNER] JOIN)은 전날이없는 첫 번째 행의 대소 문자를 보존하는 데 유용합니다.
ORDER BY을 외부 쿼리에 적용해야합니다.

+1

나는 이것이 아름답다는 것을 결정할 수 없다. 아니면 그냥 검은 마법이다. 그것은 완벽하게 작동합니다. 이해한다면 ... CTE를 사용하여 합계 행을 적절히 수집 한 다음 두 번째 및 세 번째 선택을 사용하여 필요한 CTE 내의 행을 가리키는 것입니다. 맞습니까? 감사! – Justin

+0

CTE는 로컬 임시 테이블과 같은 역할을합니다. 그래서, 네, 그게 맞을 것입니다 - 제 3 선택이 없다는 것을 제외하고는, 왼쪽 결합과 함께 단지 두번째. –

+0

. 그리고 'FROM q q1'은 CTE q를 q1로, 'LEFT JOIN q q1'을 CTE q에서 q2로, 맞습니까? 그 유형의 구문에 대한 이름이 있습니까? (즉, [구문 설명서] (http://www.postgresql.org/docs/8.1/static/sql-select.html)에서이 코드 유형을 찾거나 참조 할 수있는 곳을 찾지 못했습니다. – Justin

1

질문은 명확하지 않지만 선행/지연 행을 추적하면서 실제로 간격을 메우려는 것처럼 들립니다.

: lead()lag() 윈도우 함수에 보면, 이전 및 다음 행 값에 대한

select d 
from generate_series(timestamp '2013-12-01', timestamp '2013-12-31', interval '1 day') d; 

http://www.postgresql.org/docs/current/static/functions-srf.html

:

generate_series() 조사, 격차를 작성하고 테이블과 조인 왼쪽으로
select date_trunc('day', ts) as curr_row_day, 
     lag(date_trunc('day', ts)) over w as prev_row_day 
from data 
window w as (order by ts) 

http://www.postgresql.org/docs/current/static/tutorial-window.html

+0

@erwinbrandstetter는 대답을 얻는 데 도움이되었지만'generate_series()','lag()'및'lead()'함수는 이전에 보지 못했던 유용한 도구였습니다. 감사! – Justin

관련 문제