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

时间:2017-04-20 12:31:28

标签: postgresql plpgsql

我想使用函数/程序添加到'模板'使用多个值列出一个附加列(例如句点名称),并在行上执行笛卡尔积,这样我的模板就可以了。与为新列提供的不同值重复。

E.g。将包含2个值的句点列添加到template_country_channel表:

SELECT * 
FROM   unnest(ARRAY['P1', 'P2']) AS prd(period)
     , template_country_channel 
ORDER BY  period DESC
        , sort_cnty
        , sort_chan;

/* 
-- this is equivalent to: 
(
  SELECT   'P2'::text AS period
         , *
  FROM template_country_channel
) UNION ALL ( 
  SELECT   'P1'::text AS period
         , *
  FROM template_country_channel
)
--
*/

此查询工作正常,但我想知道是否可以将其转换为PL / pgSQL函数/过程,提供要添加的新列值,添加额外列的列(并可选择指定顺序)按条件)。

我想做的是:

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');

我有错误ERROR: 42601: a column definition list is required for functions returning “record”

经过一些谷歌搜索,似乎我需要定义列和类型列表来执行RETURN QUERY(因为错误消息准确地说明)。 不幸的是,整个想法是使用具有许多模板的功能'表,所以列名称&类型列表不固定。

  • 还有其他方法可以尝试吗?
  • 或者让它工作的唯一方法就是在函数中使用一种获取列列表的方法。 template表的名称和类型?

1 个答案:

答案 0 :(得分:0)

如果您希望输出列列表完全动态,则我用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;

然后需要调用FETCH ALL IN以获得结果。详细语法herehttps://stackoverflow.com/a/12483222/630169。看来这是目前的唯一方法。希望将在PostgreSQL 11中使用PROCEDURES进行一些更改。