将表名传递给函数并返回表
Posted
技术标签:
【中文标题】将表名传递给函数并返回表【英文标题】:Passing table name to a function and returning a table 【发布时间】:2017-03-31 01:57:27 【问题描述】:我需要在数据库的许多表(PostgreSQL 9.3.5)上运行相同的查询,并将表名作为参数传递给函数似乎是一件合乎逻辑的事情。阅读文档中的示例和众多 S.O.帖子,我还是不能确定。
使用这个最小的例子:
CREATE TABLE films (
code char(5),
kind varchar(10)
);
INSERT INTO films VALUES
('UA502', 'Comedy');
还有这个功能:
CREATE OR REPLACE FUNCTION foo(_t text)
RETURNS void AS -- I know, void is not what I am after
$func$
BEGIN
EXECUTE format('SELECT count(*) FROM %I', _t);
END
$func$ LANGUAGE plpgsql;
以下查询捕获了一些东西:
mydb=> SELECT foo('films');
foo
-----
(1 row)
但是因为我想检索一个表,所以我编辑第二行并重新创建函数,如下所示:
CREATE OR REPLACE FUNCTION foo(_t text)
RETURNS TABLE(count integer) AS
$func$
BEGIN
EXECUTE format('SELECT count(*) FROM %I', _t);
END
$func$ LANGUAGE plpgsql;
但是同样的查询没有捕获任何东西:
mydb=> SELECT foo('films');
foo
-----
(0 rows)
有人可以让我知道我在这里缺少什么以及如何继续吗?任何提示都非常感谢!
【问题讨论】:
你能试试这个吗? Return Table 查询中的 RETURN QUERY 而不是 EXECUTE 格式 关键是返回类型。如果您想要的只是一个整数列(计数),那么任务很简单。如果你想返回输入表的行,那就更复杂了。 谢谢@Erwin,我会记住这一点,因为我很快就会尝试到达那里。但对我来说,首先获得一些基本概念很重要。我觉得我什至无法进入“Hello World!”...... 顺便说一句,问题标题与问题相矛盾,因为您不是返回一个表,只是一个值。不是集合返回函数,主体不同。 【参考方案1】:如果一个函数返回一个标量值,它必须包含return <expression>
:
execute ... into ...
),
在return <expression>
中使用它。
例子:
drop function if exists foo(_t text);
create or replace function foo(_t text)
returns bigint as
$func$
declare
res bigint;
begin
execute format('select count(*) from %I', _t) into res;
return res;
end
$func$ language plpgsql;
select foo('films');
如果函数返回一个表,它必须包含return next
或return query
:
return next
,
在 FROM 子句中调用函数,而不是在 SELECT 列表中。
示例 1:
drop function if exists foo(_t text);
create or replace function foo(_t text)
returns table(count bigint) as
$func$
begin
execute format('select count(*) from %I', _t) into count;
return next;
end
$func$ language plpgsql;
select * from foo('films');
如果一个函数返回一个表,你也可以使用return query
:
示例 2:
drop function if exists foo(_t text);
create or replace function foo(_t text)
returns table(count bigint) as
$func$
begin
return query
execute format('select count(*) from %I', _t);
end
$func$ language plpgsql;
select * from foo('films');
【讨论】:
谢谢@klin。搜索return next
和 return query
也让我找到了文档的正确部分:40.6.1。从 plsql 中的函数返回。进一步阅读...【参考方案2】:
您需要带有EXECUTE
的动态SQL,并且您需要正确地转义标识符。你已经猜对了。
您在如何返回值和@klin provides solutions for that 方面遇到问题。
要传递表名,我建议使用regclass
参数。并且,为简单起见,为结果添加一个 OUT
参数:
CREATE OR REPLACE FUNCTION f_count_rows(_tbl regclass, OUT _ct bigint)
RETURNS bigint AS
$func$
BEGIN
EXECUTE 'SELECT count(*) FROM ' || _tbl INTO _ct;
END
$func$ LANGUAGE plpgsql;
这样……
您不需要手动转义表名,因为它内置在类型转换中。
最重要的是,您可以传递模式限定的表名,例如 myschema.mytable
,如果您将其传递为text
并在函数体中使用quote_ident(_tbl)
或format('... %I' _tbl)
对其进行转义。将被解释为表名"myschema.mytable"
。您必须分别传递架构和表名才能使其正常工作。
OUT
参数很方便,因为它替换了变量声明和RETURN
命令。否则等价。当函数到达控制结束时,自动返回OUT
参数的当前状态。
相关:
Table name as a PostgreSQL function parameter明确一点:RETURN
命令只是一种从函数返回标量值的方法。还有其他像我上面演示的那样,还有更多:
【讨论】:
信息量很大,这让我可以慢慢开始理解这些在各种帖子中看到的概念++以上是关于将表名传递给函数并返回表的主要内容,如果未能解决你的问题,请参考以下文章