返回给定表的动态列集的函数

问题描述 投票:0回答:2

我有一个

fields
表来存储其他表的列信息:

CREATE TABLE public.fields (
   schema_name varchar(100), 
   table_name  varchar(100), 
   column_text varchar(100), 
   column_name varchar(100), 
   column_type varchar(100) default 'varchar(100)', 
   column_visible boolean
);

我想创建一个函数来获取特定表的数据。 刚刚尝试过这样的事情:

create or replace function public.get_table(schema_name text,
                                            table_name text,
                                            active boolean default true)
  returns setof record as $$

declare 
    entity_name text default schema_name || '.' || table_name;
    r record;
begin
    for r in EXECUTE 'select * from ' || entity_name loop
        return next r;
    end loop;
    return;
end
$$
language plpgsql;

使用此函数,我在调用它时必须指定列!

select * from public.get_table('public', 'users') as dept(id int, uname text);

我想将

schema_name
table_name
作为参数传递给函数并根据
column_visible
表中的
public.fields
字段获取记录列表。

postgresql function plpgsql dynamic-sql
2个回答
12
投票

简单案例的解决方案

如下面引用的答案中所述,您可以使用注册(行)类型,从而隐式声明多态函数的返回类型:

CREATE OR REPLACE FUNCTION public.get_table(_tbl_type anyelement)
  RETURNS SETOF anyelement
  LANGUAGE plpgsql AS
$func$
BEGIN
   RETURN QUERY EXECUTE format('TABLE %s', pg_typeof(_tbl_type));
END
$func$;

调用(注意语法!):

SELECT * FROM public.get_table(NULL::public.users);

返回完整的表(包含所有用户列)。

等等!怎么办?

详细解释见相关答案章节 《各种完整的表类型》:

TABLE foo
只是
SELECT * FROM foo
的缩写:

2完全动态返回类型的步骤

但是您想要做的事情在单个 SQL 命令中是完全不可能

我想根据

schema_name
字段将
table_name
column_visible
作为参数传递给函数并获取记录列表
public.fields
桌子。

没有直接的方法可以从函数或任何 SQL 命令返回任意选择的列(调用时返回类型未知)。 SQL 要求在调用时知道结果列的数量、名称和类型。更多内容请参见相关答案的第二章:

有各种解决方法。您可以将结果包装在一种标准文档类型中(

json
jsonb
hstore
xml
)。

或者,您可以使用一个函数调用生成查询,并使用下一个函数调用执行结果:

CREATE OR REPLACE FUNCTION public.generate_get_table(_schema_name text, _table_name text)
  RETURNS text
  LANGUAGE sql AS
$func$
   SELECT format('SELECT %s FROM %I.%I'
               , string_agg(quote_ident(column_name), ', ')
               , schema_name
               , table_name)
   FROM   fields
   WHERE  column_visible
   AND    schema_name = _schema_name 
   AND    table_name  = _table_name
   GROUP  BY schema_name, table_name
   ORDER  BY schema_name, table_name;
$func$;

致电:

SELECT public.generate_get_table('public', 'users');

这将创建以下形式的查询:

SELECT usr_id, usr FROM public.users;

在第2步中执行。 (您可能想要添加列号并对列进行排序。)
或者在 psql 中追加

\gexec
来立即执行返回值。参见:

如何在加入/推送到外部服务器之前强制评估子查询

一定要防御SQL注入:

旁白

varchar(100)
对于标识符来说没有多大意义,标准 Postgres 中标识符的长度限制为 63 个字符:

如果您了解对象标识符类型

regclass
的工作原理,您可以将架构和表名称替换为单个
regclass
列。


0
投票

我认为你只需要另一个查询来获取你想要的列的列表。

也许类似(未经测试):

create or replace function public.get_table(_schema_name text, _table_name text, active boolean default true) returns setof record as $$
declare
    entity_name text default schema_name || '.' || table_name;
    r record;
    columns varchar;
begin
    -- Get the list of columns
    SELECT string_agg(column_name, ', ')
         INTO columns
         FROM public.fields
         WHERE fields.schema_name = _schema_name
            AND fields.table_name = _table_name
            AND fields.column_visible = TRUE;

    -- Return rows from the specified table
    RETURN QUERY EXECUTE 'select ' || columns || ' from ' || entity_name;

    RETURN;
end
$$
language plpgsql;

请记住,如果列/表引用中包含某些字符,则可能需要用双引号引起来。

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.