如何在PostgreSQL中的函数内返回SELECT的结果?

Ren*_*ani 92 sql postgresql return return-type plpgsql

我在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;
Run Code Online (Sandbox Code Playgroud)

但我不知道如何在PostgreSQL函数中返回查询结果.

我发现返回类型应该是SETOF RECORD,对吗?但是返回命令不对.

这样做的正确方法是什么?

Erw*_*ter 115

用途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;
Run Code Online (Sandbox Code Playgroud)

呼叫:

SELECT * FROM word_frequency(123);
Run Code Online (Sandbox Code Playgroud)

说明:

  • 这是很多更实用的明确定义的返回类型不是简单地声明为记录.这样,您不必为每个函数调用提供列定义列表.RETURNS TABLE是一种方法来做到这一点.还有其他人.OUT参数的数据类型必须与查询返回的内容完全匹配.

  • OUT仔细选择参数名称.它们在功能体中几乎可以在任何地方看到.表限定相同名称的列以避免冲突或意外结果.我在我的例子中为所有列做了那个.

    但请注意参数与同名列别名之间的潜在命名冲突.在这种特殊情况下()Postgres在参数中使用列别名.但是,在其他情况下,这可能是模棱两可的.有各种方法可以避免任何混淆:OUTcntRETURN QUERY SELECT ...OUT

    1. 使用SELECT列表中项目的序号位置:ORDER BY 2 DESC.例:
    2. 重复表达式ORDER BY count(*).
    3. (此处不适用.)设置配置参数plpgsql.variable_conflict或使用#variable_conflict error | use_variable | use_column每个功能的特殊命令.例:
  • 不要使用"text"和"count"作为列名.两者在Postgres中都是合法的,但"count"是标准SQL中的保留字和基本函数名,"text"是基本数据类型.可能导致混乱的错误.我用txtcnt在我的例子.

  • ;在标头中添加了缺失和更正的语法错误.(_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) 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;
Run Code Online (Sandbox Code Playgroud)

表达式sum(t.cnt) OVER ()是一个窗口函数.您可以使用CTE而不是子查询 - 漂亮,但在这样的简单情况下,子查询通常更便宜.

最后明确RETURN声明要求有工作的时候(但允许)OUT参数或RETURNS TABLE(使隐式使用的OUT参数).

round()两个参数仅适用于numeric类型.count()子查询产生bigint的结果和sum()在此bigint产生numeric的结果,因此,我们对付numeric自动编号和一切都只是属于地方.

  • 当您不想限制 Return TABLE() 中的内容时,有什么方法可以做到这一点。IE 返回表(*) ? (2认同)

小智 9

请参阅以下链接获取文档:

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;
Run Code Online (Sandbox Code Playgroud)