[英]Input table for PL/pgSQL function
I would like to use a plpgsql function with a table and several columns as input parameter. 我想将一个带有表和几列的plpgsql函数用作输入参数。 The idea is to split the table in chunks and do something with each part.
想法是将表拆分为多个块,并对每个部分进行处理。
I tried the following function: 我尝试了以下功能:
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()
is the function that does some work on each smaller part. my_func2()
是对每个较小部分进行一些工作的函数。
CREATE or REPLACE FUNCTION my_func2(table1)
RETURNS SETOF my_part2 AS
$$
BEGIN
RETURN QUERY
SELECT * FROM table1;
END
$$
LANGUAGE plpgsql;
If I run: 如果我运行:
SELECT * FROM my_func(99);
I guess I should receive the first 99 IDs processed for each id. 我想我应该收到为每个ID处理的前99个ID。 But it says there is an error for the following line:
但它说以下行有错误:
SELECT * FROM my_func2(select * from table1 where id = i)
The error is: 错误是:
The subquery is only allowed to return one column
子查询只允许返回一列
Why does this happen? 为什么会这样? Is there an easy way to fix this?
有简单的方法可以解决此问题吗?
There are multiple misconceptions here. 这里有多种误解 。 Study the basics before you try advanced magic.
在尝试高级魔术之前,请先学习基础知识。
Postgres does not have "table variables". Postgres没有“表变量”。 You can only pass 1 column or row at a time to a function.
一次只能将1列或1行传递给一个函数。 Use a temporary table or a
refcursor
(like commented by @Daniel) to pass a whole table. 使用临时表或
refcursor
(由@Daniel喜欢评论)通过一个完整的表。 The syntax is invalid in multiple places, so it's unclear whether that's what you are actually trying. 该语法在多个地方都是无效的,因此尚不清楚这是否是您真正要尝试的。
Even if it is: it would probably be better to process one row at a time or rethink your approach and use a set-based operation (plain SQL) instead of passing cursors. 即使是这样:一次处理一行或重新考虑您的方法并使用基于集合的操作(普通SQL)而不是传递游标可能会更好。
The data types my_part
and my_part2
are undefined in your question. 数据类型
my_part
和my_part2
在您的问题中未定义。 May be a shortcoming of the question or a problem in the test case. 可能是测试案例中的问题或问题的不足。
You seem to expect that the table name table1
in the function body of my_func2()
refers to the function parameter of the same (type!) name, but this is fundamentally wrong in at least two ways: 您似乎希望
my_func2()
函数体中的表名table1
引用相同(类型!)名称的函数参数,但是从根本上讲,这至少有两种错误:
You can only pass values . 您只能传递值 。 A table name is an identifier , not a value.
表名是标识符 ,而不是值。 You would need to build a query string dynamically and execute it with
EXECUTE
in a plpgsql function. 您将需要动态构建查询字符串,并使用plpgsql函数中的
EXECUTE
执行查询字符串。 Try a search, many related answers her on SO. 尝试搜索,因此她获得了许多相关的答案。 Then again, that may also not be what you wanted.
再说一遍,那可能也不是您想要的。
table1
in CREATE or REPLACE FUNCTION my_func2(table1)
is a type name , not a parameter name. table1
在CREATE or REPLACE FUNCTION my_func2(table1)
是一种类型的名称 ,而不是参数名称。 It means your function expects a value of the type table1
. 这意味着您的函数需要一个
table1
类型的值。 Obviously, you have a table of the same name, so it's supposed to be the associated row type. 显然,您有一个同名的表,因此它应该是关联的行类型。
The RETURN type of my_func2()
must match what you actually return. my_func2()
的RETURN类型必须与您实际返回的内容匹配。 Since you are returning SELECT * FROM table1
, make that RETURNS SETOF table1
. 由于您要返回
SELECT * FROM table1
,因此请使RETURNS SETOF table1
成为可能。
It can just be a simple SQL function. 它可以只是一个简单的SQL函数。
All of that put together: 所有这些放在一起:
CREATE or REPLACE FUNCTION my_func2(_row table1)
RETURNS SETOF table1 AS
'SELECT ($1).*' LANGUAGE sql;
Note the parentheses, which are essential for decomposing a row type. 请注意括号,这对于分解行类型至关重要。 Per documentation:
每个文档:
The parentheses are required here to show that
compositecol
is a column name not a table name此处需要括号以表明
compositecol
是列名而不是表名
But there is more ... 但是还有更多...
Don't use
as variable name, it's a keyword of the out
CREATE FUNCTION
statement. 不要
作为变量名,它是out
CREATE FUNCTION
语句的关键字。
The syntax of your main query my_func()
is more like psudo-code. 您的主要查询
my_func()
的语法更像是伪代码。 Too much doesn't add up. 太多不会加起来。
Demo table: 演示表:
CREATE TABLE table1(table1_id serial PRIMARY KEY, txt text);
INSERT INTO table1(txt) VALUES ('a'),('b'),('c'),('d'),('e'),('f'),('g');
Helper function: 辅助功能:
CREATE or REPLACE FUNCTION my_func2(_row table1)
RETURNS SETOF table1 AS
'SELECT ($1).*' LANGUAGE sql;
Main function: 主功能:
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;
Call: 呼叫:
SELECT * FROM my_func(99);
But it's really just aa proof of concept. 但这实际上只是概念的证明。 Nothing useful, yet.
没什么用。
As the error log is telling you.. you can return only one column in a subquery, so you have to change it to 错误日志告诉您..您只能在子查询中返回一列,因此您必须将其更改为
SELECT my_func2(SELECT Specific_column_you_need FROM hasval WHERE wid = i)
a possible solution can be that you pass to funct2 the primary key of the table your funct2 needs and then you can obtain the whole table by making the SELECT * inside the function 一种可能的解决方案是,将funct2所需的表的主键传递给funct2,然后通过在函数内部进行SELECT *,可以获取整个表
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.