使用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 是一种方法。还有其他的。 OUT 参数的数据类型必须与查询返回的内容完全匹配。
仔细选择OUT 参数的名称。它们几乎在函数体中的任何地方都可见。对同名的列进行表限定以避免冲突或意外结果。我对示例中的所有列都这样做了。
但请注意OUT 参数cnt 与同名的列别名之间可能存在命名冲突。在这种特殊情况下 (RETURN QUERY SELECT ...),Postgres 使用列别名而不是 OUT 参数。不过,这在其他情况下可能会模棱两可。有多种方法可以避免混淆:
- 使用 SELECT 列表中项目的序号位置:
ORDER BY 2 DESC。例子:
- 重复表达式
ORDER BY count(*)。
- (此处不适用。)设置配置参数
plpgsql.variable_conflict或在函数中使用特殊命令#variable_conflict error | use_variable | use_column。看:
不要使用“text”或“count”作为列名。在 Postgres 中使用两者都是合法的,但“count”是标准 SQL 中的 reserved word 和基本函数名称,“text”是基本数据类型。可能导致令人困惑的错误。我在示例中使用了txt 和cnt,您可能需要更明确的名称。
添加了缺失的; 并更正了标头中的语法错误。 (_max_tokens int),不是 (int maxTokens) - type 在 name 之后。
在使用整数除法时,最好先乘后除,以尽量减少舍入误差。或者使用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 () 是window function。您可以使用CTE 代替子查询。很漂亮,但是在像这样的简单情况下(主要是在 Postgres 12 之前),子查询通常更便宜。
使用OUT 参数或RETURNS TABLE(隐式使用OUT 参数)时的最终explicit RETURN statement is not required(但允许)。
round() with two parameters 仅适用于 numeric 类型。子查询中的count() 产生一个bigint 结果,而sum() 在这个bigint 上产生一个numeric 结果,因此我们自动处理一个numeric 数字,一切就位。