2016-07-27 13 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')で簡単な自己結合を行うことはできません。同様に、単純なウィンドウも機能しません。

ほとんどの場合、現在の行に基づく条件付きウィンドウフレームが必要です。それはPostgreSQLで可能ですか?

+0

解決策の1つは、 '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; 

はるかに高価になります。数ヶ月ではなく、常に30日ですので、それは常に暦月に整列していますが、この場合、あなたは義務、うまく動作するはずインデックス

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

関連する問題