9

PostgreSQLのウィンドウ上で動作するUDFの作成に何が関係しているのかをもっとよく理解したいと思います。一般的なUDFの作成方法について検索しましたが、ウィンドウ上で動作するUDFの作成方法の例は見つかりませんでした。

そのために、ウィンドウ内の数値の移動平均を計算するUDF(C、pl / SQL、またはPostgreSQLでサポートされている手続き型言語のいずれか)の記述方法のコードを誰かが喜んで共有してくれることを期待しています。標準の平均集計関数をウィンドウ構文(私が信じる構文間の行)で適用することでこれを行う方法があることに気付きました。これは良い単純な例になると思うので、単にこの機能を求めています。また、平均関数のウィンドウバージョンがあった場合、データベースは実行中の合計と観測数を保持でき、各反復でほぼ同じ行のセットを合計することはできないと思います。

4

4 に答える 4

8

postgresqlソースコードpostgresql/src / backend / utils / adt/windowfuncs.cおよびpostgresql/src / backend / executer/nodeWindowAgg.cを確認する必要があります

良いドキュメントはありません:(-完全に機能するウィンドウ関数はCまたはPL/v8でのみ実装する必要があります-他の言語用のAPIはありません。

http://www.pgcon.org/2009/schedule/track/Version%208.4/128.en.htmlPostgreSQLでの実装の作成者によるプレゼンテーション。

非コア実装が1つだけ見つかりました-http://api.pgxn.org/src/kmeans/kmeans-1.1.0/

http://pgxn.org/dist/plv8/1.3.0/doc/plv8.html

于 2012-12-09T19:27:59.360 に答える
5

ドキュメントによると、「他のウィンドウ関数はユーザーが追加できます。また、組み込みまたはユーザー定義の通常の集計関数をウィンドウ関数として使用できます。」(セクション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);

2つのテーブルのスキーマは次のとおりです。

CREATE TABLE demo.prices_raw (
  id VARCHAR(30),
  vd DATE,
  rawprice float8 );

CREATE TABLE demo.adjustments (
  id VARCHAR(30),
  vd DATE,
  sdiv float);
于 2015-06-23T03:42:59.263 に答える
3

テーブルから始める

支払い
+ ------------------------------ +
| customer_id | 金額| アイテム|
| 5 | 10 | 本|
| 5 | 71 | マウス|
| 7 | 13 | カバー|
| 7 | 22 | ケーブル|
| 7 | 19 | 本|
+ ------------------------------ +
SELECT customer_id, 
    AVG(amount) OVER (PARTITION BY customer_id) AS avg_amount,   
    item, 
FROM payments`

我々が得る

+ ---------------------------------- +
| customer_id | avg_amount | アイテム|
| 5 | 40.5 | 本|
| 5 | 40.5 | マウス|
| 7 | 18 | カバー|
| 7 | 18 | ケーブル|
| 7 | 18 | 本|
+ ---------------------------------- +

AVG集計関数であるため、ウィンドウ関数として機能できます。ただし、すべてのウィンドウ関数が集計関数であるとは限りません。集計関数は、洗練されていないウィンドウ関数です。

上記のクエリでは、組み込みAVG関数を使用せず、独自の実装を使用しましょう。同じことを行いますが、ユーザーが実装しただけです。上記のクエリは次のようになります。

SELECT customer_id, 
    my_avg(amount) OVER (PARTITION BY customer_id) AS avg_amount,   
    item, 
FROM payments`

以前のクエリとの唯一の違いは、AVGに置き換えられていることmy_avgです。次に、カスタム関数を実装する必要があります。

平均の計算方法について

すべての要素を合計してから、要素の数で割ります。customer_id7の場合、それはになります(13 + 22 + 19) / 3 = 18。私たちはそれを次のように考案することができます:

  • ステップバイステップの累積-合計。
  • 最終操作-除算。

集計関数が結果に到達する方法について

平均は段階的に計算されます。最後の値のみが必要です。初期値0から始めます。

  1. フィード13.中間/累積合計を計算します。これは13です。
  2. フィード22.累積合計を計算します。これには、前の合計とこの要素が必要です。13 + 22 = 35
  3. フィード19.前の合計とこの要素を必要とする累積合計を計算します35 + 19 = 54。これは、要素の数(3)で割る必要がある合計です。
  4. 手順3の結果は、累積合計を要素数で除算する方法を知っている別の関数に送られます。

ここで起こったことは、状態が初期値0から始まり、ステップごとに変更されてから、次のステップに渡されることです。

データがある限り、状態はステップ間を移動します。すべてのデータが消費されると、状態は最終機能(端末操作)になります。状態には、アキュムレータと端末操作に必要なすべての情報が含まれている必要があります。

平均を計算する特定のケースでは、端末操作は、アキュムレータで除算する必要があるため、アキュムレータが処理した要素の数を知る必要があります。そのため、状態には累積合計と要素数の両方を含める必要があります。

両方を含むタプルが必要です。事前定義されPOINTたPostgreSQLタイプが役に立ちます。POINT(5、89)は、89の値を持つ5つの要素の累積合計を意味します。初期状態はPOINT(0,0)になります。

アキュムレータは、いわゆる状態関数で実装されます。ターミナル操作は、いわゆる最終関数で実装されます。

カスタム集計関数を定義するときは、以下を指定する必要があります。

  • 集計関数名と戻り値のタイプ
  • 初期状態
  • インフラストラクチャがステップ間および最終機能に渡される状態のタイプ
  • 状態関数-累積ステップを実行する方法を知っています
  • 最後の機能-端末操作の実行方法を知っています。常に必要なわけではありません(たとえば、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 
);

残っているのは、2つの関数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に、より高度な基準に応じて、グループ内のすべての行に対して異なる値を返します)
  • いずれにせよ、値はすべての行で同じであるため、PARTITIONing時にORDERBYを使用しても意味がありません。対照的に、私たちは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
);
于 2018-12-17T11:29:04.420 に答える
0

PL/Rはそのような機能を提供します。いくつかの例については、ここを参照してください。とはいえ、「現在、実行中の合計と観測数を維持し、各反復でほぼ同一の行のセットを合計しない」という要件を満たしているかどうかはわかりません(ここを参照) 。 。

于 2013-05-21T14:21:24.473 に答える