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/pgSQLSQL 函数CREATE FUNCTION的优秀手册。

为什么这个例子是废话的要点

  • 首先,你不能像你一样交出一个标识符。标识符不能在普通 SQL 中参数化。为此,您需要动态 SQL
    当然,根据您的要求,您实际上并不需要它。只涉及一张桌子。尝试参数化它是无稽之谈。

  • 不要使用类型名称作为标识符。我使用_date而不是date作为参数名称并将您的表列重命名为asset_date. ALTER您的表定义相应。

  • 从表中获取数据的函数永远不会是IMMUTABLE. 阅读手册。

  • 您以荒谬的方式将 SQL 语法与 plpgsql 元素混合在一起。WITHSELECT语句的一部分,不能与 plpgsql 控制结构(如LOOPor )混合使用IF

适当的功能

正确的函数可能如下所示(多种方式之一):

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_change, 可以在 a 内完成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 回答