如何在postgres中执行存储过程的字符串结果

How to execute a string result of a stored procedure in postgres

我创建了以下存储过程,它基本上接收表名和前缀。该函数然后查找共享此前缀和 returns 的所有列作为 'select' 查询命令 ('myoneliner') 的输出。 如下:

CREATE OR REPLACE FUNCTION mytext (mytable text, myprefix text)
RETURNS text AS $myoneliner$
declare
    myoneliner text;
BEGIN
   SELECT 'SELECT ' || substr(cols,2,length(cols)-2) ||' FROM '||mytable 
   INTO myoneliner  
     FROM (
        SELECT array(
           SELECT DISTINCT quote_ident(column_name::text)
           FROM   information_schema.columns
           WHERE  table_name = mytable
           AND    column_name LIKE myprefix||'%'
           order by quote_ident             
      )::text cols 
     ) sub;
   RETURN myoneliner;
END;
$myoneliner$ LANGUAGE plpgsql;

致电:

select mytext('dkj_p_k27ac','enri');

作为运行此存储过程及其后的 'select' 的结果,我在数据输出 window 中得到以下输出(全部在一个单元格中,名为 "mytext text"):

'SELECT enrich_d_dkj_p_k27ac,enrich_lr_dkj_p_k27ac,enrich_r_dkj_p_k27ac
 FROM dkj_p_k27ac'

我希望基本上能够将收到的输出命令行作为输出并执行它。换句话说,我希望能够并执行我的存储过程的输出。 我该怎么做?

我尝试了以下方法:

CREATE OR REPLACE FUNCTION mytext (mytable text, myprefix text)
RETURNS SETOF RECORD AS $$
declare
        smalltext text;
    myoneliner text;
BEGIN
   SELECT 'SELECT ' || substr(cols,2,length(cols)-2) ||' FROM '||mytable 
   INTO myoneliner  
     FROM (
        SELECT array(
           SELECT DISTINCT quote_ident(column_name::text)
           FROM   information_schema.columns
           WHERE  table_name = mytable
           AND    column_name LIKE myprefix||'%'
           order by quote_ident             
      )::text cols 
     ) sub;

   smalltext=lower(myoneliner);
   raise notice '%','my additional text '||smalltext;
   RETURN QUERY EXECUTE smalltext;
END;
$$ LANGUAGE plpgsql;

调用函数:

SELECT * from mytext('dkj_p_k27ac','enri');

但是我收到以下错误消息,请问我应该更改什么才能执行它?:

ERROR:  a column definition list is required for functions returning "record"
LINE 26: SELECT * from mytext('dkj_p_k27ac','enri');

********** Error **********

ERROR: a column definition list is required for functions returning "record"
SQL state: 42601
Character: 728

你的第一个问题是通过使用动态 SQL 和 EXECUTE 解决的,就像克雷格建议的那样。 但兔子洞更深:

CREATE OR REPLACE FUNCTION myresult(mytable text, myprefix text)
  RETURNS SETOF RECORD AS
$func$
DECLARE
   <strike>smalltext  text;</strike>
   myoneliner text;
BEGIN
   SELECT INTO myoneliner  
          'SELECT '
        || string_agg(quote_ident(column_name::text), ',' ORDER BY column_name)
        || ' FROM ' || quote_ident(mytable)
   FROM   information_schema.columns
   WHERE  table_name = mytable
   AND    column_name LIKE myprefix||'%'
   AND    table_schema = 'public';  -- schema name; might be another param

   <strike>smalltext := lower(myoneliner);</strike>  -- nonsense
   RAISE NOTICE 'My additional text: %', myoneliner;

   RETURN QUERY EXECUTE myoneliner;
END
$func$ LANGUAGE plpgsql;

要点

  • 不要将整个语句转换为小写。列名可能用大写字母双引号引起来,在这种情况下区分大小写(没有双关语意)。

  • 您在 information_schema.columns 的查询中不需要 DISTINCT。列名是唯一的 per table.

  • do 需要指定模式,但是(或者使用另一种方式来挑出 一个模式),或者您可能在多个模式中混合来自多个table的同名列名,导致无意义。

  • 您必须清理动态代码中的 所有 标识符 - 包括 table 个名称:quote_ident(mytable)。请注意,函数的文本参数区分大小写! information_schema.columns 上的查询也需要这样做。

  • 我解开了你的整个结构,用 string_agg() 而不是数组构造函数来构建列名列表。相关回答:

    • Update multiple columns that start with a specific string
  • The assignment operator in plpgsql is :=.

  • RAISE NOTICE.

  • 的简化语法

无法解决的核心问题

所有这些仍然不能解决您的主要问题:SQL 需要定义要return 的列。您可以像您尝试的那样通过 returning 匿名记录来规避此问题。但这只是推迟了inevitable。现在您必须在调用时 提供列定义列表,就像您的错误消息告诉您的那样。但您只是不知道哪些列将被 returned。赶上 22.

你的调用这样工作:

SELECT *
FROM   myresult('dkj_p_k27ac','enri') AS f (
  enrich_d_dkj_p_k27ac text  -- replace with actual column types
, enrich_lr_dkj_p_k27ac text
, enrich_r_dkj_p_k27ac text);

但是您不知道 returned 列的编号、名称(可选)和数据类型,在创建函数时不知道,甚至在调用时也不知道。 不可能单个调用中做到这一点。您需要两个单独的数据库查询

可以return所有列的任何给定table 使用 多态类型 动态地使用函数,因为整个 table 有一个明确定义的类型。本相关回答最后一章:

  • Refactor a PL/pgSQL function to return the output of various SELECT queries