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)
LANGUAGE plpgsql 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$;
電話:
SELECT * FROM word_frequency(123);
リターンタイプを明示的に定義することは多くです 一般的なrecord
を返すよりも実用的です 。このように、すべての関数呼び出しで列定義リストを提供する必要はありません。 RETURNS TABLE
それを行う1つの方法です。他にもあります。 OUT
のデータ型 パラメータは、クエリによって返されるものと正確に一致する必要があります。
OUT
の名前を選択してください パラメータを慎重に。それらは、関数本体のほぼどこにでも表示されます。競合や予期しない結果を回避するために、同じ名前の列をテーブル修飾します。私の例では、すべての列に対してこれを行いました。
ただし、名前の競合の可能性に注意してください OUT
の間 パラメータcnt
および同じ名前の列エイリアス。この特定のケースでは(RETURN QUERY SELECT ...
)PostgresはOUT
に対して列エイリアスを使用します どちらの方法でもパラメータ。ただし、これは他のコンテキストではあいまいになる可能性があります。混乱を避けるにはさまざまな方法があります:
- SELECTリスト内のアイテムの序数位置を使用します:
ORDER BY 2 DESC
。例:- 各GROUPBYグループの最初の行を選択しますか?
- 式
ORDER BY count(*)
を繰り返します 。 - (ここでは適用されません。)構成パラメーター
plpgsql.variable_conflict
を設定します。 または、特別なコマンド#variable_conflict error | use_variable | use_column
関数内。参照:- 関数パラメータとUSING句を使用したJOINの結果の間の名前の競合
列名として「テキスト」または「カウント」を使用しないでください。どちらもPostgresでの使用は合法ですが、「カウント」は予約語です。 標準SQLでは基本的な関数名であり、「テキスト」は基本的なデータ型です。紛らわしいエラーにつながる可能性があります。 txt
を使用しています およびcnt
私の例では、より明確な名前が必要な場合があります。
不足している;
を追加しました ヘッダーの構文エラーを修正しました。 (_max_tokens int)
、(int maxTokens)
ではありません -タイプ 名前の後 。
整数除算を使用する場合は、丸め誤差を最小限に抑えるために、最初に乗算して後で除算することをお勧めします。またはnumeric
を使用します または浮動小数点型。以下を参照してください。
代替
これが私が考えている クエリは実際には次のようになります(トークンごとの相対シェアの計算 ):
CREATE OR REPLACE FUNCTION word_frequency(_max_tokens int)
RETURNS TABLE (txt text
, abs_cnt bigint
, relative_share numeric)
LANGUAGE plpgsql 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$;
式sum(t.cnt) OVER ()
ウィンドウ関数です。あなたはできた サブクエリの代わりにCTEを使用します。かなりですが、このような単純なケースでは、サブクエリの方が一般的に安価です(ほとんどの場合、Postgres 12より前)。
最後の明示的なRETURN
ステートメントはではありません OUT
を使用する場合は必須(ただし許可) パラメータまたはRETURNS TABLE
(これはOUT
を暗黙的に使用します パラメータ)。
round()
2つのパラメータを使用すると、numeric
でのみ機能します タイプ。 count()
サブクエリでbigint
を生成します 結果とsum()
このbigint
numeric
を生成します 結果として、numeric
を処理します 自動的に番号が付けられ、すべてが適切に配置されます。