如何在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必须完全匹配查询返回的内容。

  • 仔细selectOUT参数的名称。 它们几乎在任何地方都可以在function体中看到。 表格 – 限定相同名称的列以避免冲突或意外的结果。 我做了我的例子中的所有列。

    但请注意OUT参数cnt和同名的列别名之间的潜在命名冲突 。 在这种特殊情况下( RETURN QUERY SELECT ... )Postgres以任何方式使用OUT参数的列别名。 但是,在其他情况下,这可能是不明确的。 有各种方法可以避免混淆:

    1. 在SELECT列表中使用该项目的序号位置: ORDER BY 2 DESC 。 例:
      • 在每个GROUP BY组中select第一行?
    2. 重复expression式ORDER BY count(*)
    3. (这里不适用)设置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结果之间的冲突
  • 不要使用“文本”和“计数”作为列名。 两者在Postgres中都是合法的,但“count”是标准SQL中的保留字 ,基本的函数名称,“text”是基本的数据types。 可能导致混淆错误。 我在我的例子中使用txtcnt

  • 增加了一个失踪; 并纠正了标题中的语法错误。 (_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()仅适用于numerictypes。 在子查询中count()产生一个bigint结果,并且sum()通过这个bigint产生一个numeric结果,因此我们自动处理一个numeric数字,所有东西都落在原地。