输入 table 用于 PL/pgSQL 函数

Input table for PL/pgSQL function

我想使用带有 table 和多个列的 plpgsql 函数作为输入参数。这个想法是将 table 分成几块,然后对每个部分做一些事情。

我尝试了以下功能:

CREATE OR REPLACE FUNCTION my_func(Integer)
  RETURNS SETOF my_part
AS $$
DECLARE
out my_part;
BEGIN
  FOR i IN 0.. LOOP
    FOR out IN
    SELECT * FROM my_func2(SELECT * FROM table1 WHERE id = i)
    LOOP
       RETURN NEXT out;
   END LOOP;
  END LOOP;
  RETURN;
END;
$$
LANGUAGE plpgsql;

my_func2() 是对每个较小部分做一些工作的函数。

CREATE or REPLACE FUNCTION my_func2(table1) 
  RETURNS SETOF my_part2 AS
$$ 
BEGIN
RETURN QUERY
SELECT * FROM table1;
END
$$
LANGUAGE plpgsql;

如果我运行:

SELECT * FROM my_func(99);

我想我应该收到为每个 ID 处理的前 99 个 ID。 但它说以下行有错误:

SELECT * FROM my_func2(select * from table1 where id = i)

错误是:

The subquery is only allowed to return one column

为什么会这样?有解决这个问题的简单方法吗?

正如错误日志告诉您的那样..您只能 return 子查询中的一列,因此您必须将其更改为

SELECT my_func2(SELECT Specific_column_you_need FROM hasval WHERE wid = i)

一个可能的解决方案是,你将你的 funct2 需要的 table 的主键传递给 funct2,然后你可以通过在里面创建 SELECT * 来获得整个 table函数

这里有多个误解。在尝试高级魔法之前学习基础知识。

  • Postgres 没有 "table variables"。您一次只能将 1 列或行传递给函数。使用临时 table 或 refcursor(如@Daniel 评论的那样)来传递整个 table。该语法在多个地方无效,因此不清楚这是否是您实际尝试的内容。
    即使是:一次处理一行或重新考虑您的方法并使用基于集合的操作(普通 SQL)而不是传递游标可能会更好。

  • 数据类型 my_partmy_part2 在您的问题中未定义。可能是题目的不足,也可能是测试用例的问题。

  • 您似乎期望my_func2()函数体中的table名称table1指的是相同(类型!)名称的函数参数,但这至少在两个方面是根本错误的:

    1. 您只能传递 。 table 名称是一个 标识符 ,而不是一个值。您需要动态构建查询字符串并在 plpgsql 函数中使用 EXECUTE 执行它。 Try a search, many related answers her on SO.话又说回来,这也可能不是你想要的。

    2. table1 in CREATE or REPLACE FUNCTION my_func2(table1) 类型名称 ,不是参数名称。这意味着您的函数需要 table1 类型的值。显然,您有一个同名的 table,因此它应该是关联的行类型。

  • my_func2() 的 RETURN 类型必须与您实际 return 匹配。由于您正在 returning SELECT * FROM table1,因此 RETURNS SETOF table1.

  • 可以只是一个简单的SQL函数。

所有这些放在一起:

CREATE or REPLACE FUNCTION my_func2(_row table1) 
  RETURNS SETOF table1 AS
'SELECT ().*' LANGUAGE sql;

注意括号,这对于分解行类型是必不可少的。 Per documentation:

The parentheses are required here to show that compositecol is a column name not a table name

但还有更多...

  • 不要使用out作为变量名,它是CREATE FUNCTION语句的关键字。

  • 您的主查询 my_func() 的语法更像是伪代码。加多了也不行。

概念验证

演示 table:

CREATE TABLE table1(table1_id serial PRIMARY KEY, txt text);
INSERT INTO table1(txt) VALUES ('a'),('b'),('c'),('d'),('e'),('f'),('g');

辅助函数:

CREATE or REPLACE FUNCTION my_func2(_row table1) 
  RETURNS SETOF table1 AS
'SELECT ().*' LANGUAGE sql;

主要功能:

CREATE OR REPLACE FUNCTION my_func(int)
  RETURNS SETOF table1 AS
$func$
DECLARE
   rec table1;
BEGIN
  FOR i IN 0.. LOOP
     FOR rec IN
        SELECT * FROM table1 WHERE table1_id = i
     LOOP
        RETURN QUERY
        SELECT * FROM my_func2(rec);
     END LOOP;
  END LOOP;
END
$func$  LANGUAGE plpgsql;

致电:

SELECT * FROM my_func(99);

SQL Fiddle.

但这实际上只是概念验证。还没有什么用。