postgresql 如何从下一行引用数据?

px9o7tmv  于 2022-11-04  发布在  PostgreSQL
关注(0)|答案(2)|浏览(155)

我正在用PostgreSQL 9.2编写一个函数。
对于包含股票价格和日期的表,我希望计算每个条目相对于前一天的百分比变化。对于数据的最早日期,将没有前一天,因此该条目可以简单地为零。
我知道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$;

如何正确引用下一行的数据?

rlcwz9us

rlcwz9us1#

我想计算每个条目与前一天相比的百分比变化

先学习基础知识。阅读关于CREATE FUNCTIONPL/pgSQLSQL functions的优秀手册。

这个例子毫无意义的主要原因

  • 你不能像你那样提交一个标识符。标识符不能在普通SQL中参数化。你需要动态SQL

当然,实际上你的目标并不需要。这里只涉及一个表。将它参数化是没有意义的。

  • 不要使用类型名作为标识符。我使用_date而不是date作为参数名,并相应地将您的表列重命名为asset_dateALTER您的表定义。
  • 从表中获取数据的函数永远不会是IMMUTABLE。不要将其声明为Read the manual.
  • 您正在以无意义的方式混合SQL语法和PL/pgSQL元素。WITHSELECT语句的一部分,不能与LOOPIF等PL/pgSQL控制结构混合。

已清理的函数

一个适当的函数可能如下所示(多种方式之一):

CREATE FUNCTION percentage_change_func(_asset_symbol text)
  RETURNS TABLE(asset_date date, price numeric, pct_change numeric)
  LANGUAGE plpgsql STABLE AS
$func$
DECLARE
   last_price numeric;
BEGIN
   FOR asset_date, price IN
      SELECT a.asset_date, a.price  -- table-qualify to disambiguate!
      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$;

性能应该不会这么差,但还是毫无意义的复杂化。

正确的解决方案:普通查询

最简单(也可能是最快)的方法是使用窗口函数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;

标准偏差

根据您后面的评论,您希望计算统计数字,如标准差。
Postgres有专门的统计数据聚合函数

4c8rllxm

4c8rllxm2#

像计算per_change这样简单的事情,可以在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'

相关问题