我真的想更好地了解什么是参与创建工作在PostgreSQL中窗口一个UDF。 我做了一些搜索有关如何在通用的UDF创建,但还没有找到如何做一个工作在窗口的例子。
为此,我希望有人愿意分享如何写一个UDF代码(可在C,PL / SQL或任何PostgreSQL支持的程序语言)计算的数字在窗口中运行的平均值。 我知道有办法通过与窗口语法采用标准平均聚合函数做这个(语法之间行,我相信),我只是要求这个功能,因为我觉得这也是一个不错的简单的例子。 另外,我觉得如果有平均功能的窗口版本,则数据库可以保持运行总和和观察计数,并在每次迭代不会总结行几乎相同的套。
你必须寻找到PostgreSQL源代码的PostgreSQL /文件src / backend / utils的/ ADT / windowfuncs.c和PostgreSQL / src目录/后端/执行/ nodeWindowAgg.c
有没有好的文档:( - 全功能窗口功能只能在C或PL / V8可以实现 - 也有其他语言的API。
http://www.pgcon.org/2009/schedule/track/Version%208.4/128.en.html从PostgreSQL中实现的作者的介绍。
我发现只有一个非核心实现- http://api.pgxn.org/src/kmeans/kmeans-1.1.0/
http://pgxn.org/dist/plv8/1.3.0/doc/plv8.html
根据文档 “ 的其他窗函数可以由用户来添加。另外,任何内建或用户定义的正常聚集体功能可作为一个窗口函数。”(见第4.2.8)。 这为我工作计算股票分割的调整:
CREATE OR REPLACE FUNCTION prod(float8, float8) RETURNS float8
AS 'SELECT $1 * $2;'
LANGUAGE SQL IMMUTABLE STRICT;
CREATE AGGREGATE prods ( float8 ) (
SFUNC = prod,
STYPE = float8,
INITCOND = 1.0
);
create or replace view demo.price_adjusted as
select id, vd,
prods(sdiv) OVER (PARTITION by id ORDER BY vd DESC ROWS UNBOUNDED PRECEDING) as adjf,
rawprice * prods(sdiv) OVER (PARTITION by id ORDER BY vd DESC ROWS UNBOUNDED PRECEDING) as price
from demo.prices_raw left outer join demo.adjustments using (id,vd);
下面是这两个表的模式:
CREATE TABLE demo.prices_raw (
id VARCHAR(30),
vd DATE,
rawprice float8 );
CREATE TABLE demo.adjustments (
id VARCHAR(30),
vd DATE,
sdiv float);
PL / R提供这样的功能。 见这里的一些例子。 这就是说,我不知道它(目前)满足您的“养[和]运行总和和观察计数和[不]和[明]了几乎相同的设置在每次迭代行的”要求(见这里 ) 。
与表开始
payments
+------------------------------+
| customer_id | amount | item |
| 5 | 10 | book |
| 5 | 71 | mouse |
| 7 | 13 | cover |
| 7 | 22 | cable |
| 7 | 19 | book |
+------------------------------+
SELECT customer_id,
AVG(amount) OVER (PARTITION BY customer_id) AS avg_amount,
item,
FROM payments`
我们得到
+----------------------------------+
| customer_id | avg_amount | item |
| 5 | 40.5 | book |
| 5 | 40.5 | mouse |
| 7 | 18 | cover |
| 7 | 18 | cable |
| 7 | 18 | book |
+----------------------------------+
AVG
是一个聚合函数,它可以作为一个窗口函数。 然而,并非所有的窗函数聚合函数。 聚合函数是不复杂的窗函数。
在上面的查询,我们不要用内置AVG
功能和使用我们自己的实现。 不一样的,只是由用户来实现。 上面的查询变为:
SELECT customer_id,
my_avg(amount) OVER (PARTITION BY customer_id) AS avg_amount,
item,
FROM payments`
从以前的查询唯一不同的是, AVG
已经替换为my_avg
。 现在,我们需要实现我们的自定义功能。
关于如何计算平均
总结所有的元素,然后通过元素的数量鸿沟。 对于customer_id
7,这将是(13 + 22 + 19) / 3 = 18
。 我们可以devide它:
在聚合函数如何得到的结果
平均计算中的步骤。 只有最后一个值是必要的。 开始为0的初始值。
- 订阅13.计算中间/累加和,这是13。
- 订阅22.计算累加和,需要前面的总和加上该元素:
13 + 22 = 35
- 订阅19.计算累加和,需要前面的总和加上该元素:
35 + 19 = 54
。 这是需要由元件(3)的数目被划分总。 - 步骤3的结果被馈送到另一个功能,它知道如何通过元件的数目来划分累加和
这里发生了什么,就是国家开始的初始值为0的每一步改变,然后传递给下一个步骤。
国家只要有数据步骤之间传播。 当所有数据被消耗状态变为一个最终功能(终端操作)。 我们希望国家包含所需蓄电池以及终端操作的所有信息。
在计算平均值的特定情况下,终端操作需要知道蓄电池多少元素,因为它需要通过划分工作。 出于这个原因,该状态需要同时包括累加和与元件的数量。
我们需要一个元组将包含两个。 预定义POINT
PostgreSQL类型救援。 点(5,89)是指具有89的值的初始状态将是一个点(0,0)5种元素的累积总和。
蓄电装置处于什么叫做状态函数来实现。 终端操作在什么所谓的最终功能实现。
当定义一个自定义的聚合函数,我们需要指定:
- 聚集函数名和返回类型
- 初始状态
- 该基础设施将步骤之间和到最后的功能传递状态的种类
- 状态函数 - 知道如何进行积累步骤
- 最终的功能 - 知道如何进行终端操作。 并不总是需要(例如SUM的自定义实现累计总和的终值是结果。)
下面是自定义聚集函数的定义。
CREATE AGGREGATE my_avg (NUMERIC) ( -- NUMERIC is what the function returns
initcond = '(0,0)', -- this is the initial state of type POINT
stype = POINT, -- this is the type of the state that will be passed between steps
sfunc = my_acc, -- this is the function that knows how to compute a new average from existing average and new element. Takes in the state (type POINT) and an element for the step (type NUMERIC)
finalfunc my_final_func -- returns the result for the aggregate function. Takes in the state of type POINT (like all other steps) and returns the result as what the aggregate function returns - NUMERIC
);
唯一剩下的就是定义两个函数my_acc
和my_final_func
。
CREATE FUNCTION my_acc (state POINT, elem_for_step NUMERIC) -- performs accumulated sum
RETURNS POINT
LANGUAGE SQL
AS $$
-- state[0] is the number of elements, state[1] is the accumulated sum
SELECT POINT(state[0]+1, state[1] + elem_for_step);
$$;
CREATE FUNCTION my_final_func (POINT) -- performs devision and returns final value
RETURNS NUMERIC
LANGUAGE SQL
AS $$
-- $1[1] is the sum, $1[0] is the number of elements
SELECT ($1[1]/$1[0])::NUMERIC;
$$;
现在,该功能可CREATE AGGREGATE
上面定义的成功运行。 现在,我们已经聚集定义的基础上,查询my_avg
,而不是内置AVG
可以运行:
SELECT customer_id,
my_avg(amount) OVER (PARTITION BY customer_id) AS avg_amount,
item,
FROM payments`
结果与你使用内置的时候得到什么相同AVG
。
PostgreSQL文档表明用户被限制为实现用户定义的集合函数:
除了这些[预先定义的窗]的功能,任何内建或用户定义的通用或统计集合(即,不是有序集或假想集聚集体)可以被用作一个窗函数;
我怀疑ordered-set or hypothetical-set aggregates
是指:
- 返回的值是相同的所有其他行(例如
AVG
和SUM
。相比之下RANK
所有行组中根据更复杂的标准将返回不同的值) - 这是没有意义的ORDER分区时,因为值是所有行相同反正BY。 相反,我们要
ORDER BY
当使用RANK()
查询:
SELECT customer_id, item, rank() OVER (PARTITION BY customer_id ORDER BY amount desc) FROM payments;
几何平均数
以下是用户定义的聚合函数,我发现没有内建聚集,可能是一些有用的。
国家函数计算方面的自然对数的平均值。
最终的功能提出了不断e
到任何蓄电池提供。
CREATE OR REPLACE FUNCTION sum_of_log(state POINT, curr_val NUMERIC)
RETURNS POINT
LANGUAGE SQL
AS $$
SELECT POINT(state[0] + 1,
(state[1] * state[0]+ LN(curr_val))/(state[0] + 1));
$$;
CREATE OR REPLACE FUNCTION e_to_avg_of_log(POINT)
RETURNS NUMERIC
LANGUAGE SQL
AS $$
select exp($1[1])::NUMERIC;
$$;
CREATE AGGREGATE geo_mean (NUMBER)
(
stype = NUMBER,
initcond = '(0,0)', -- represent POINT value
sfunc = sum_of_log,
finalfunc = e_to_avg_of_log
);
文章来源: How to create a custom windowing function for PostgreSQL? (Running Average Example)