Postgresql 函数 return 多个 select 语句

Postgresql function return multiple select statements

你们谁能告诉我如何解决这个问题:

CREATE OR REPLACE FUNCTION name()
  RETURNS ????? AS
$func$
BEGIN

 SELECT * FROM tbl_a a;

 SELECT * FROM tbl_b b;

END
$func$ LANGUAGE plpgsql;

两个表的结构不同。

你可以使用游标,但我很难想象你为什么需要这样的功能。

CREATE OR REPLACE FUNCTION my_multiselect(refcursor, refcursor) RETURNS VOID AS
  $func$
BEGIN
  OPEN  FOR SELECT * FROM information_schema.routines;
  OPEN  FOR SELECT * FROM information_schema.sequences;
END
$func$ LANGUAGE plpgsql;

BEGIN;
SELECT my_multiselect('first_cursor_to_routines', 'second_cursor_to_sequences');
FETCH ALL IN first_cursor_to_routines;
FETCH ALL IN second_cursor_to_sequences;
COMMIT;

我不太确定你用这个做什么,但听起来你只是想 return 这些不同结果集的联合。您可以使用动态查询来执行此操作。我正在使用 Postgres 9.4。

CREATE OR REPLACE FUNCTION make_query(IN p_tables text[])
  RETURNS void AS
$BODY$
DECLARE
    v_qry text;
    v_cols text;
    v_types text;
    v_as text;
BEGIN
EXECUTE format('
    WITH sub AS (
        SELECT 
            table_name, 
            column_name, 
            data_type 
        FROM 
            information_schema.columns 
        WHERE 
            table_name = ANY(%L)
        ORDER BY 
            table_name, 
            ordinal_position)
    ,sub2 AS(
        SELECT
            DISTINCT ON (column_name, data_type)
            column_name || '' '' || data_type AS def
        FROM
            sub
    )
    SELECT
        string_agg(def, '','')
    FROM
        sub2;
',
    p_tables
) INTO v_types;

v_qry := '
        CREATE OR REPLACE FUNCTION name()
          RETURNS TABLE(' || v_types || ') AS
        $func$';

FOR i IN 1..array_upper(p_tables, 1)    
LOOP

    v_as := 'tbl' || i;

    EXECUTE format('
        WITH sub AS (
            SELECT 
                table_name, 
                column_name, 
                data_type 
            FROM 
                information_schema.columns 
            WHERE 
                table_name = ANY(%L)
            ORDER BY 
                table_name, 
                ordinal_position)
        ,sub2 AS(
            SELECT
                DISTINCT ON (column_name, data_type)
                CASE WHEN table_name = ''%I'' 
                    THEN %L || ''.'' || column_name 
                    ELSE ''NULL::'' || data_type 
                END AS cols
            FROM
                sub
        )
        SELECT
            string_agg(cols, '','')
        FROM
            sub2;
    ',
        p_tables,
        p_tables[i],
        v_as
    ) INTO v_cols;

    IF i > 1 THEN
        v_qry := v_qry || '
UNION ALL'; 
    END IF;

    v_qry := v_qry || '
SELECT ' || v_cols || ' FROM ' || p_tables[i] || ' AS ' || v_as;

    IF i = array_upper(p_tables, 1) THEN 
        v_qry := v_qry || ';'; 
    END IF;

END LOOP;
v_qry := v_qry || '
$func$ LANGUAGE sql;
';

EXECUTE v_qry;
END;
$BODY$
LANGUAGE plpgsql VOLATILE;

抱歉,这里看起来很丑陋,但这种格式有助于最终产品看起来更漂亮。如果您对立即执行这样的动态查询感到害羞,只需将 EXECUTE v_qry; 替换为 RAISE INFO 'v_qry: %', v_qry; ,它只会在消息中打印出动态查询而不执行它,因此您可以查看内容它会执行一次。

然后执行 make_query() 和您要显示的表格列表,如下所示:

SELECT make_query(ARRAY['tbl_a', 'tbl_b']);

结果是您现在将拥有一个名为 name() 的函数,您可以调用该函数以同时查看两个表的结果,所有联合详细信息都已整理出来:

SELECT * FROM name();