PL / pgSQL函数的输入表

时间:2015-01-08 14:01:14

标签: sql postgresql plpgsql

我想使用带有表和多列作为输入参数的plpgsql函数。我们的想法是将表格拆分成块并对每个部分做一些事情。

我尝试了以下功能:

CREATE OR REPLACE FUNCTION my_func(Integer)
  RETURNS SETOF my_part
AS $$
DECLARE
out my_part;
BEGIN
  FOR i IN 0..$1 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)

错误是:

  

子查询只允许返回一列

为什么会这样?有没有一种简单的方法来解决这个问题?

2 个答案:

答案 0 :(得分:3)

此处有多个误解。在尝试高级魔术之前先研究基础知识。

  • Postgres没有“表变量”。您一次只能将1列或行传递给函数。使用临时表或refcursor(如@Daniel评论)传递整个表。语法在多个地方无效,因此不清楚这是否是您实际尝试的内容 即使它是:最好一次处理一行或重新思考你的方法并使用基于集合的操作(普通SQL)而不是传递游标。

  • 您的问题中未定义数据类型my_partmy_part2。可能是测试用例中问题或问题的缺点。

  • 您似乎期望table1的函数体中的表名my_func2()引用相同(类型!)名称的函数参数,但这在根本上是错误的至少有两种方式:

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

    2. {li>

      table1中的CREATE or REPLACE FUNCTION my_func2(table1)类型名称,而不是参数名称。这意味着您的函数需要类型table1的值。显然,你有一个同名的表,所以它应该是相关的行类型。

  • my_func2()的RETURN类型必须与实际返回的匹配。由于您要返回SELECT * FROM table1,请将其设为RETURNS SETOF table1

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

所有这些放在一起:

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

请注意括号,这对于分解行类型至关重要。 Per documentation:

  

此处需要括号表示compositecol是列名而不是表名

但还有更多......

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

  • 主查询my_func()的语法更像是psudo-code。太多不加起来。

概念证明

演示表:

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 ($1).*' LANGUAGE sql;

主要功能:

CREATE OR REPLACE FUNCTION my_func(int)
  RETURNS SETOF table1 AS
$func$
DECLARE
   rec table1;
BEGIN
  FOR i IN 0..$1 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.

但它实际上只是一个概念证明。没什么用的。

答案 1 :(得分:0)

由于错误日志告诉您..您只能返回子查询中的一列,因此您必须将其更改为

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

一个可能的解决方案是你可以将funct2所需的表的主键传递给funct2然后你可以通过在函数内部使用SELECT *来获得整个表