将表名传递给函数并返回表

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 nextreturn 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 nextreturn 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 命令只是一种从函数返回标量值的方法。还有其他像我上面演示的那样,还有更多:

Can I make a plpgsql function return an integer without using a variable?

【讨论】:

信息量很大,这让我可以慢慢开始理解这些在各种帖子中看到的概念++

以上是关于将表名传递给函数并返回表的主要内容,如果未能解决你的问题,请参考以下文章

将表名从外部或变量传递给 INSERT INTO 表名?

如何动态地将表名传递给 PL SQL 游标?

每个将表名传递给过程的 ORACLE PL/SQL

存储过程:将表名转换为表变量

如何将表名和选定字段作为参数传递

[mysql-connector-python在将表作为参数传递时,在表名周围添加单引号。表名来自Flask会话变量