2016-07-27 2 views
5

의 나는 다음과 같은 테이블이 있다고 가정 해 봅시다 :PostgreSQL - 조건이있는 창 프레임은 어떻게 만듭니 까?

CREATE TABLE stock_prices (
    stock TEXT NOT NULL, 
    date DATE NOT NULL, 
    price REAL NOT NULL, 
    UNIQUE (stock, date) 
); 

내가 이전 3 개월의 창에서 매일 각 주식의 최고 가격을 계산합니다.

stock_price 테이블에 공휴일과 주말을위한 "홀"이 있기 때문에 간단한 자체 조인을 date - INTERVAL(3 'MONTH')으로 수행 할 수 없습니다. 비슷하게 순진한 창도 작동하지 않습니다.

SELECT 
    stock, 
    date, 
    LAST_VALUE(price) OVER (PARTITION BY stock ORDER BY date ROWS 90 PRECEDING) 
FROM stock_prices 

나는 현재 행에 기반한 조건을 가진 창 프레임을 거의 원합니다. PostgreSQL에서도 가능합니까?

+0

하나의 해결책은'generate_series()'를 사용하여 추가 행을 생성하는 것입니다. –

+0

문제 없음 : * 날짜 범위에 * 구멍 *이있는 경우 * 구멍 *에 최대 가격을 포함 할 수 없습니다. – joop

+0

dba.se : [창 함수를 사용하는 날짜 범위 롤링 합계] (http://dba.stackexchange.com/q/114403/57105)에서 논의되었습니다. dba.se의 질문은 SQL Server를 사용하지만 최신 Postgres와 최신 SQL Server는 Window 기능과 관련된 기능이 동일하므로 응답을 Postgres에 최소한의 변경만으로 적용 할 수 있습니다. 이 두 가지 모두'RANGE' 창 프레임을 지원하지 않습니다.이 프레임 프레임은이 질문에서 중요합니다. 하위 쿼리를 사용하거나 @klin이 보여주는 날짜의 구멍을 채 웁니다. –

답변

5

generate_series() 함수를 사용하여 누락 된 행으로 표를 채울 수 있으므로 창 함수가 올바른 데이터를 반환합니다. 당신은 generate_series()에서 시작 및 종료 날짜를 지정 보고서의 기간을 선택할 수 있습니다

select 
    stock, 
    date, 
    price, 
    max(price) over (partition by stock order by date rows 90 preceding) 
from (
    select d::date as date, s.stock, sp.price 
    from generate_series('2016-01-01'::date, '2016-07-28', '1d') g(d) 
    cross join (
     select distinct stock 
     from stock_prices 
    ) s 
    left join stock_prices sp on g.d = sp.date and s.stock = sp.stock 
) s 
order by 1, 2; 

간단한 하위 쿼리와이 대체 솔루션 :

select 
    stock, 
    date, 
    price, 
    (
     select max(price) 
     from stock_prices sp2 
     where sp2.stock = sp1.stock 
     and sp2.date >= sp1.date- interval '90days' 
     and sp2.date <= sp1.date 
    ) highest_price 
from 
    stock_prices sp1 
order by 1, 2; 

훨씬 더 비싼 것입니다. 달은 항상 삼십일 때문에 항상 일정 달에 정렬되지 않습니다 있지만,이 경우에는 의무, 잘 작동한다 인덱스

create index on stock_prices (stock, date); 
0

generate_series 옵션을 사용해야합니다.

간격을 사용하려는 경우 자체 조인 및 집계를 수행 할 수도 있습니다. 이것은 (이 경우에는 내가 1 주 간격을 설정 한) 조건에 맞는 모든 행에 각 행을 결합하고, 그 결과 세트 내에서 최대 값을 얻을 것이다 :

select a.stock, 
     a.date, 
     a.price, 
     max(b.price) 
from stock_prices as a 
     left join 
     stock_prices as b 
     on a.stock = b.stock 
     and b.date between (a.date - interval '7 days') and a.date 
group by a.stock, 
     a.date, 
     a.price 
order by a.stock, 
     a.date 

SQL 바이올린 여기 : http://sqlfiddle.com/#!15/bbec8/2