PostgreSQLにはこの関数がありますが、クエリの結果を返す方法がわかりません。
CREATE OR REPLACE FUNCTION wordFrequency(maxTokens INTEGER)
RETURNS SETOF RECORD AS
$$
BEGIN
SELECT text, count(*), 100 / maxTokens * count(*)
FROM (
SELECT text
FROM token
WHERE chartype = 'ALPHABETIC'
LIMIT maxTokens
) as tokens
GROUP BY text
ORDER BY count DESC
END
$$
LANGUAGE plpgsql;
しかし、PostgreSQL関数内でクエリの結果を返す方法がわかりません。
戻り値の型はSETOF RECORD
である必要があることがわかりました。しかし、戻りコマンドは正しくありません。
これを行う正しい方法は何ですか?
使用RETURN QUERY
:
CREATE OR REPLACE FUNCTION Word_frequency(_max_tokens int)
RETURNS TABLE (txt text -- also visible as OUT parameter inside function
, cnt bigint
, ratio bigint) AS
$func$
BEGIN
RETURN QUERY
SELECT t.txt
, count(*) AS cnt -- column alias only visible inside
, (count(*) * 100) / _max_tokens -- I added brackets
FROM (
SELECT t.txt
FROM token t
WHERE t.chartype = 'ALPHABETIC'
LIMIT _max_tokens
) t
GROUP BY t.txt
ORDER BY cnt DESC; -- potential ambiguity
END
$func$ LANGUAGE plpgsql;
コール:
SELECT * FROM Word_frequency(123);
説明:
単純にレコードとして宣言するよりも、戻り値の型を明示的に定義する方がmuchより実用的です。この方法では、すべての関数呼び出しで列定義リストを提供する必要はありません。 RETURNS TABLE
はそれを行う1つの方法です。他にもあります。 OUT
パラメーターのデータ型は、クエリによって返されるものと正確に一致する必要があります。
OUT
パラメーターの名前は慎重に選択してください。それらはほとんどどこでも関数本体で見ることができます。競合または予期しない結果を避けるために、同じ名前の列をテーブル修飾します。私の例では、すべての列に対してこれを行いました。
ただし、OUT
パラメーターcnt
と同じ名前の列エイリアスとの間の潜在的な命名競合に注意してください。この特定の場合(RETURN QUERY SELECT ...
)Postgresは、OUT
パラメーターで列エイリアスを使用します。ただし、これは他のコンテキストではあいまいになる場合があります。混乱を避けるためのさまざまな方法があります。
ORDER BY 2 DESC
。例:ORDER BY count(*)
を繰り返します。plpgsql.variable_conflict
を設定するか、関数で特別なコマンド#variable_conflict error | use_variable | use_column
を使用します。見る:列名として「テキスト」または「カウント」を使用しないでください。両方ともPostgresでの使用は合法ですが、「count」は、標準SQLの 予約語 です。 「テキスト」は基本的なデータ型です。混乱を招くエラーにつながる可能性があります。私の例ではtxt
とcnt
を使用しています。
欠落している;
を追加し、ヘッダーの構文エラーを修正しました。 (_max_tokens int)
ではなく(int maxTokens)
-nameの後のtype。
整数除算を使用する場合、丸め誤差を最小限に抑えるために、最初に乗算し、後で除算することをお勧めします。さらに良い:numeric
(または浮動小数点型)を使用します。下記参照。
これは、クエリが実際にどのように見えるべきかと思う(トークンごとに相対シェアを計算する):
CREATE OR REPLACE FUNCTION Word_frequency(_max_tokens int)
RETURNS TABLE (txt text
, abs_cnt bigint
, relative_share numeric) AS
$func$
BEGIN
RETURN QUERY
SELECT t.txt, t.cnt
, round((t.cnt * 100) / (sum(t.cnt) OVER ()), 2) -- AS relative_share
FROM (
SELECT t.txt, count(*) AS cnt
FROM token t
WHERE t.chartype = 'ALPHABETIC'
GROUP BY t.txt
ORDER BY cnt DESC
LIMIT _max_tokens
) t
ORDER BY t.cnt DESC;
END
$func$ LANGUAGE plpgsql;
式sum(t.cnt) OVER ()
は ウィンドウ関数 です。あなたはcouldサブクエリの代わりに CTE を使用します-きれいですが、サブクエリはこのような単純なケースでは一般的に安価です。
最後の 明示的なRETURN
ステートメントはnotが必要です (ただし許可されています)OUT
パラメーターまたはRETURNS TABLE
(OUT
パラメーターの暗黙的な使用)を使用する場合.
round()
パラメータが2つ は、のみで機能します- numeric
タイプ。サブクエリのcount()
はbigint
の結果を生成し、このbigint
に対するsum()
はnumeric
の結果を生成します。したがって、自動的にnumeric
数を処理し、すべてが適切に配置されます。
こんにちは、以下のリンクを確認してください
https://www.postgresql.org/docs/current/xfunc-sql.html
例:
CREATE FUNCTION sum_n_product_with_tab (x int)
RETURNS TABLE(sum int, product int) AS $$
SELECT $1 + tab.y, $1 * tab.y FROM tab;
$$ LANGUAGE SQL;