我是PostgreSQL的新手,在这里编写函数很难实现。所以我希望有人能帮助我知道如何做我想做的事。
我有一张股票价格和日期表。我想计算每个条目前一天的变化百分比。对于数据的最早日期,将不会有前一天,因此输入可以简单地为零。有人可以查看我的功能并帮助我
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。
答案 0 :(得分:8)
我想计算每一天的前一天的变化百分比 条目。
一般来说,在开始提问之前,你需要学习基础知识
阅读关于CREATE FUNCTION
,PL/pgSQL和SQL functions的优秀手册。
首先,您不能像您一样提交标识符。标识符不能在纯SQL中参数化。你需要dynamic SQL 当然,根据您的要求,您实际上并不需要这样做。只涉及一个表。尝试参数化是没有意义的。
不要使用类型名称作为标识符。我使用_date
代替date
作为参数名称,并将您的表格列重命名为asset_date
。相应地ALTER
你的表定义。
从表中获取数据的函数永远不能是IMMUTABLE
。 Read the manual.
您正在以无意义的方式将SQL语法与plpgsql元素混合。 WITH
是SELECT
语句的一部分,不能与LOOP
或IF
等plpgsql控件结构混合使用。
正确的功能可能看起来像这样(多种方式之一):
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中有专门的aggregate functions for statistics。
答案 1 :(得分:0)
简单的事情,比如计算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'