Postgresql函数返回多个select语句

时间:2015-05-06 10:35:34

标签: postgresql postgresql-9.3

你们中的任何人都可以告诉我如何处理这个问题:

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

 SELECT * FROM tbl_a a;

 SELECT * FROM tbl_b b;

END
$func$ LANGUAGE plpgsql;

两个表都有不同的结构。

2 个答案:

答案 0 :(得分:0)

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

CREATE OR REPLACE FUNCTION my_multiselect(refcursor, refcursor) RETURNS VOID AS
  $func$
BEGIN
  OPEN $1 FOR SELECT * FROM information_schema.routines;
  OPEN $2 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;

答案 1 :(得分:0)

我不确定你在做什么,但听起来你只想返回这些不同结果集的联合。您可以使用动态查询执行此操作。我正在使用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();