输入 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_part
和 my_part2
在您的问题中未定义。可能是题目的不足,也可能是测试用例的问题。
您似乎期望my_func2()
函数体中的table名称table1
指的是相同(类型!)名称的函数参数,但这至少在两个方面是根本错误的:
您只能传递 值。 table 名称是一个 标识符 ,而不是一个值。您需要动态构建查询字符串并在 plpgsql 函数中使用 EXECUTE
执行它。 Try a search, many related answers her on SO.话又说回来,这也可能不是你想要的。
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);
但这实际上只是概念验证。还没有什么用。
我想使用带有 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_part
和my_part2
在您的问题中未定义。可能是题目的不足,也可能是测试用例的问题。您似乎期望
my_func2()
函数体中的table名称table1
指的是相同(类型!)名称的函数参数,但这至少在两个方面是根本错误的:您只能传递 值。 table 名称是一个 标识符 ,而不是一个值。您需要动态构建查询字符串并在 plpgsql 函数中使用
EXECUTE
执行它。 Try a search, many related answers her on SO.话又说回来,这也可能不是你想要的。table1
inCREATE or REPLACE FUNCTION my_func2(table1)
是 类型名称 ,不是参数名称。这意味着您的函数需要table1
类型的值。显然,您有一个同名的 table,因此它应该是关联的行类型。
my_func2()
的 RETURN 类型必须与您实际 return 匹配。由于您正在 returningSELECT * 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);
但这实际上只是概念验证。还没有什么用。