如何在PostgreSQL中的函数内返回SELECT的结果?
我在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函数中返回查询的结果。
我发现返回types应该是SETOF RECORD
,对不对? 但是,返回命令是不正确的。
什么是正确的方法来做到这一点?
使用RETURN QUERY
:
CREATE OR REPLACE FUNCTION word_frequency(_max_tokens int) RETURNS TABLE ( txt text -- visible as OUT parameter inside and outside 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; -- note the potential ambiguity END $func$ LANGUAGE plpgsql;
呼叫:
SELECT * FROM word_frequency(123);
说明:
-
显式定义返回types比简单地将其声明为logging要实用得多。 这样,您不必为每个函数调用提供列定义列表。
RETURNS TABLE
是一种方法。 还有其他的。OUT
参数的数据types必须完全匹配查询返回的内容。 -
仔细select
OUT
参数的名称。 它们几乎在任何地方都可以在function体中看到。 表格 – 限定相同名称的列以避免冲突或意外的结果。 我做了我的例子中的所有列。但请注意
OUT
参数cnt
和同名的列别名之间的潜在命名冲突 。 在这种特殊情况下(RETURN QUERY SELECT ...
)Postgres以任何方式使用OUT
参数的列别名。 但是,在其他情况下,这可能是不明确的。 有各种方法可以避免混淆:- 在SELECT列表中使用该项目的序号位置:
ORDER BY 2 DESC
。 例:- 在每个GROUP BY组中select第一行?
- 重复expression式
ORDER BY count(*)
。 - (这里不适用)设置configuration参数
plpgsql.variable_conflict
或使用特殊命令#variable_conflict error | use_variable | use_column
#variable_conflict error | use_variable | use_column
每个函数的#variable_conflict error | use_variable | use_column
。 例:- 使用USING子句命名函数参数和JOIN结果之间的冲突
- 在SELECT列表中使用该项目的序号位置:
-
不要使用“文本”和“计数”作为列名。 两者在Postgres中都是合法的,但“count”是标准SQL中的保留字 ,基本的函数名称,“text”是基本的数据types。 可能导致混淆错误。 我在我的例子中使用
txt
和cnt
。 -
增加了一个失踪
;
并纠正了标题中的语法错误。(_max_tokens int)
,not(int maxTokens)
– 在名称后键入 。 -
在使用整数除法时,最好先乘以后再去除,以最小化舍入误差。 甚至更好:使用
numeric
(或浮点types)。 见下文。
替代
这是我认为你的查询应该看起来像(计算每个令牌的相对份额 ):
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 ()
expression式是一个窗口函数 。 你可以使用CTE而不是子查询 – 漂亮,但是在这种简单的情况下子查询通常更便宜。
当使用OUT
参数或RETURNS TABLE
(隐式使用OUT
参数)时, 不需要 (但允许)最后的显式RETURN
语句 。
具有两个参数的round()
仅适用于numeric
types。 在子查询中count()
产生一个bigint
结果,并且sum()
通过这个bigint
产生一个numeric
结果,因此我们自动处理一个numeric
数字,所有东西都落在原地。