PostgreSQL equivalent of Oracle “bulk collect”

限于喜欢 提交于 2019-11-29 18:10:10

There is no such syntax in PostgreSQL, nor a close functional equivalent.

You can create a temporary table in your PL/PgSQL code and use that for the desired purpose. Temp tables in PL/PgSQL are a little bit annoying because the names are global within the session, but they work correctly in PostgreSQL 8.4 and up.

A better alternative for when you're doing all the work within a single SQL statement is to use a common table expression (CTE, or WITH query). This won't be suitable for all situations.

The example above would be much better solved by a simple RETURN QUERY in PL/PgSQL, but I presume your real examples are more complex.

Assuming that tb_person is some kind of expensive-to-generate view that you don't just want to scan in each branch of the union, you could do something like:

CREATE OR REPLACE FUNCTION prc_tst_bulk()
RETURNS TABLE (name text, rowcount integer) AS 
$$
BEGIN
    RETURN QUERY
    WITH v_tb_person AS (SELECT * FROM tb_person)
    select name, count(*) from v_tb_person where age > 50
    union 
    select name, count(*) from v_tb_person where gender = 1;
END;
$$ LANGUAGE plpgsql;

This particular case can be further simplified into a plain SQL function:

CREATE OR REPLACE FUNCTION prc_tst_bulk()
RETURNS TABLE (name text, rowcount integer) AS 
$$
    WITH v_tb_person AS (SELECT * FROM tb_person)
    select name, count(*) from v_tb_person where age > 50
    union 
    select name, count(*) from v_tb_person where gender = 1;
$$ LANGUAGE sql;

You can use a PostgreSQL arrays too - it is similar to Oracle's collections:

postgres=# create table _foo(a int, b int);
CREATE TABLE
postgres=# insert into _foo values(10,20);
INSERT 0 1

postgres=# create or replace function multiply()
returns setof _foo as $$
/*
 * two tricks are here
 * table name can be used as type name
 * table name can be used as fictive column that packs all fields
 */
declare a _foo[] = (select array(select _foo from _foo));
begin
  return query select * from unnest(a) 
           union
           all select * from unnest(a);
end;
$$ language plpgsql;

CREATE FUNCTION
postgres=# select * from multiply();
 a  | b  
----+----
 10 | 20
 10 | 20
(2 rows)

But in your case Craig Ringer's proposal is perfect and should be preferable.

In PostgreSQL 10 you can use array_agg:

declare
    v_ids int[];   
begin
    select array_agg(id) INTO v_ids
      from mytable1
     where host = p_host;

    --use v_ids...

end;

You'll have array and it can be used to make select from it using unnest:

select * from unnest(v_ids) where ...
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!