Postgresql 使用PL/pgSQL函数将具有多个值的列动态添加到任何表中

Postgresql 使用PL/pgSQL函数将具有多个值的列动态添加到任何表中,postgresql,plpgsql,Postgresql,Plpgsql,我想使用一个函数/过程向“模板”表中添加一个附加列,例如具有多个值的期间名称,并对行进行笛卡尔乘积,以便使用为新列提供的不同值复制我的“模板” 例如,在“我的模板”\u country\u channel表中添加一个具有2个值的句点列: 该查询工作正常,但我想知道是否可以将其转换为PL/pgSQL函数/过程,提供要添加的新列值、要向其中添加额外列的列,以及可选地指定order by条件 我想做的是: SELECT * FROM template_with_periods( 'tem

我想使用一个函数/过程向“模板”表中添加一个附加列,例如具有多个值的期间名称,并对行进行笛卡尔乘积,以便使用为新列提供的不同值复制我的“模板”

例如,在“我的模板”\u country\u channel表中添加一个具有2个值的句点列:

该查询工作正常,但我想知道是否可以将其转换为PL/pgSQL函数/过程,提供要添加的新列值、要向其中添加额外列的列,以及可选地指定order by条件

我想做的是:

SELECT * 
FROM template_with_periods(
      'template_country_channel'           -- table name
    , ARRAY['P1', 'P2']                    -- values for the new column to be added
    , 'period DESC, sort_cnty, sort_chan'  -- ORDER BY string (optional)
);
并具有与第一个查询相同的结果

因此,我创建了一个函数,如:

CREATE OR REPLACE FUNCTION template_with_periods(template regclass, periods text[], order_by text) 
    RETURNS SETOF RECORD 
AS $BODY$

BEGIN
    RETURN QUERY EXECUTE 'SELECT * FROM unnest($2) AS prd(period), $1 ORDER BY $3' USING template, periods, order_by ;


END;
$BODY$
LANGUAGE 'plpgsql'
;
但当我跑步时:

SELECT * 
FROM template_with_periods('template_country_channel', ARRAY['P1', 'P2'], 'period DESC, sort_cnty, sort_chan');
我有一个错误:42601:返回“record”的函数需要列定义列表

在谷歌搜索之后,我似乎需要定义列和类型的列表来执行返回查询,因为错误消息正好说明了这一点。 不幸的是,整个想法是将该函数用于许多“模板”表,因此列名称和类型列表不是固定的

还有其他方法可以尝试吗? 或者,使其工作的唯一方法是在函数中提供一种获取列名称列表和模板表类型的方法吗? 如果您希望输出列列表完全动态,我使用refcursor执行此操作:

CREATE OR REPLACE FUNCTION is_record_exists(tablename character varying, columns character varying[], keepcolumns character varying[] DEFAULT NULL::character varying[])
    RETURNS SETOF refcursor AS
$BODY$

DECLARE 
    ref refcursor;
    keepColumnsList text;
    columnsList text; 
    valuesList text;
    existQuery text;
    keepQuery text;
BEGIN
    IF keepcolumns IS NOT NULL AND array_length(keepColumns, 1) > 0 THEN
        keepColumnsList :=  array_to_string(keepColumns, ', ');
    ELSE
        keepColumnsList :=  'COUNT(*)';
    END IF;

    columnsList := (SELECT array_to_string(array_agg(name || ' = ' || value), ' OR ') FROM
        (SELECT unnest(columns[1:1]) AS name, unnest(columns[2:2]) AS value) pair);

    existQuery := 'SELECT ' || keepColumnsList || ' FROM ' || tableName || ' WHERE ' || columnsList;
    RAISE NOTICE 'Exist query: %', existQuery;

    OPEN ref FOR EXECUTE
        existQuery;
    RETURN next ref;
END;$BODY$
  LANGUAGE plpgsql;
然后需要调用fetchall-IN以获得结果。详细语法或有:。看来这是目前唯一的办法。希望PostgreSQL 11中的程序能有所改变。

如果您希望输出列列表完全动态,我使用refcursor进行了此操作:

CREATE OR REPLACE FUNCTION is_record_exists(tablename character varying, columns character varying[], keepcolumns character varying[] DEFAULT NULL::character varying[])
    RETURNS SETOF refcursor AS
$BODY$

DECLARE 
    ref refcursor;
    keepColumnsList text;
    columnsList text; 
    valuesList text;
    existQuery text;
    keepQuery text;
BEGIN
    IF keepcolumns IS NOT NULL AND array_length(keepColumns, 1) > 0 THEN
        keepColumnsList :=  array_to_string(keepColumns, ', ');
    ELSE
        keepColumnsList :=  'COUNT(*)';
    END IF;

    columnsList := (SELECT array_to_string(array_agg(name || ' = ' || value), ' OR ') FROM
        (SELECT unnest(columns[1:1]) AS name, unnest(columns[2:2]) AS value) pair);

    existQuery := 'SELECT ' || keepColumnsList || ' FROM ' || tableName || ' WHERE ' || columnsList;
    RAISE NOTICE 'Exist query: %', existQuery;

    OPEN ref FOR EXECUTE
        existQuery;
    RETURN next ref;
END;$BODY$
  LANGUAGE plpgsql;

然后需要调用fetchall-IN以获得结果。详细语法或有:。看来这是目前唯一的办法。希望PostgreSQL 11中的程序能有所改变。

整个想法是将该函数用于许多“模板”表,因此列名和类型列表不是固定的-这不是问题:使用RETURNS SETOF RECORD,您需要在调用端登记列名和类型,f.ex。从带有句点的模板中选择*。。。作为tperiod text、sort_cnty int、sort_chan text实际上这意味着我必须在编写查询时指定列名/类型,并且我必须知道每个表结构-非常繁琐,如果pgsql允许,这正是我想要避免的。不,不幸的是,它不允许。您需要定义输出的确切结构。在函数定义中,或者在调用端使用RETURNS SETOF RECORD。整个想法是将函数用于许多“模板”表,因此列名称和类型列表不是固定的-这不是问题:使用RETURNS SETOF RECORD,您需要在调用端登记列名和类型,f.ex。从带有句点的模板中选择*。。。作为tperiod text、sort_cnty int、sort_chan text实际上这意味着我必须在编写查询时指定列名/类型,并且我必须知道每个表结构-非常繁琐,如果pgsql允许,这正是我想要避免的。不,不幸的是,它不允许。您需要定义输出的确切结构。在函数定义内,或在调用端返回一组记录。