7

私はPostgreSQLを初めて使用し、ここで関数を書くのは非常に困難です。だから、誰かが私がやろうとしていることをする方法を教えてくれることを願っています.

株価と日付の表があります。各エントリの前日からの変化率を計算したいと思います。データの最も早い日の場合、前日がないため、エントリは単純に Nil になります。誰かが私の関数を調べて、 a)
次の行からデータを参照する方法と
b) クリーンアップを手伝ってくれませんか?

WITHステートメントがステートメントの上にあるはずがないことは承知していIFます。しかし、論理的には、これが私がこれまで考えてきた方法であり、したがって私がそれを書いた方法です。それがどのように見えるべきかアドバイスできれば、それも非常にありがたいです。

CREATE FUNCTION percentage_change_func(asset_histories) RETURNS 
numeric LANGUAGE sql IMMUTABLE AS $func$

DECLARE
r asset_histories%rowtype
BEGIN   
WITH twodaysdata AS (SELECT date,price,asset_symbol FROM asset_histories 
           WHERE asset_symbol = $1.asset_symbol 
           AND asset_histories.date <= $1.date 
           ORDER BY date DESC LIMIT 2), 
         numberofrecords AS (SELECT count(*) FROM twodaysdata) 

IF numberofrecords = 2 THEN
        RETURN r.price / (r+1).price - 1  <---How do I reference r + 1??/
ELSE
        RETURN NIL
ENDIF
END
$func$

PostgreSQL 9.2。

4

2 に答える 2

14

各エントリの前日からの変化率を計算したいと思います。

一般的に、質問を始める前に基本を勉強する必要があります。PL/pgSQLおよびSQL 関数に関する優れた
マニュアルを読んでください。CREATE FUNCTION

例がナンセンスである主なポイント

  • まず、あなたのように識別子を渡すことはできません。プレーン SQL では識別子をパラメータ化できません。そのためには動的SQLが必要です。
    もちろん、要件によると、実際には必要ありません。関連するテーブルは 1 つだけです。それをパラメータ化しようとするのはナンセンスです。

  • 型名を識別子として使用しないでください。パラメータ名_dateの代わりに使用し、テーブルの列の名前を に変更しました。それに応じてテーブル定義。dateasset_dateALTER

  • テーブルからデータを取得する関数は、IMMUTABLE. マニュアルを読んでください。

  • 無意味な方法で SQL 構文と plpgsql 要素を混在させています。WITHはステートメントの一部であり、やのSELECTような plpgsql 制御構造と混在させることはできません。LOOPIF

適切な機能

適切な関数は次のようになります (多くの方法の 1 つ)。

CREATE FUNCTION percentage_change_func(_asset_symbol text)
  RETURNS TABLE(asset_date date, price numeric, pct_change numeric) AS
$func$
DECLARE
   last_price numeric;
BEGIN

FOR asset_date, price IN
   SELECT a.asset_date, a.price
   FROM   asset_histories a
   WHERE  a.asset_symbol = _asset_symbol 
   ORDER  BY a.asset_date  -- traverse ascending
LOOP
   pct_change := price / last_price; -- NULL if last_price is NULL
   RETURN NEXT;
   last_price := price;
END LOOP;

END
$func$ LANGUAGE plpgsql STABLE

パフォーマンスはそれほど悪くないはずですが、それは無意味な複雑さです。

適切な解決策: 単純なクエリ

最も簡単な (そしておそらく最速の) 方法は、ウィンドウ関数を使用することlag()です。

SELECT asset_date, price
      ,price / lag(price) OVER (ORDER BY asset_date) AS pct_change
FROM   asset_histories
WHERE  asset_symbol = _asset_symbol 
ORDER  BY asset_date;

標準偏差

後のコメントによると、標準偏差などの統計数値を計算したいと考えています。PostgreSQLには統計
専用の集計関数があります。

于 2013-03-30T08:17:08.450 に答える
0

を計算するだけのような単純なことは、代わりにper_changea 内で行うことができますview。これにより、より高速な結果が得られます。

create view view_stock_details AS ( SELECT 
    date, 
    price, 
    symbol, 
    pervious_day_close, 
    (price-pervious_day_close)/pervious_day_close*100 as per_change 
FROM (
    SELECT
        date,
        price,
        symbol,
        ( SELECT price FROM asset_histories t WHERE t.symbol = outers.symbol AND t.date < outers.date limit 1 ) as pervious_day_close
    FROM 
        asset_histories as outers
    ); 

在庫の詳細を表示するには、次を使用できます

SELECT 
    *
FROM
    view_stock_details
WHERE
    date = '2012-01-03' 
    AND symbol = 'A'
于 2013-03-30T06:02:27.023 に答える