PostgreSQL相当于Oracle“批量收集”

时间:2013-04-29 22:22:19

标签: postgresql plpgsql

在PostgreSQL中存在一些使用批量收集的声明的方法,就像在Oracle中一样?

Oracle中的示例:

create or replace procedure prc_tst_bulk_test is

type typ_person is table of tb_person%rowtype;
v_tb_person typ_person;

begin

select *
bulk collect into v_tb_person
from tb_person;

-- make a selection in v_tb_person, for instance    
select name, count(*) from v_tb_person where age > 50
union 
select name, count(*) from v_tb_person where gender = 1

end;

谢谢

4 个答案:

答案 0 :(得分:5)

PostgreSQL中没有这样的语法,也没有相近的功能等同。

您可以在PL / PgSQL代码中创建临时表,并将其用于所需目的。 PL / PgSQL中的临时表有点烦人,因为这些名称在会话中是全局的,但它们在PostgreSQL 8.4及更高版本中正常工作。

当您在单个SQL语句中执行所有工作时,更好的替代方法是使用公用表表达式(CTE或WITH查询)。这并不适合所有情况。

上面的例子可以通过PL / PgSQL中的简单RETURN QUERY更好地解决,但我认为你的真实例子更复杂。

假设tb_person是某种昂贵的生成视图,您不仅想要在联合的每个分支中进行扫描,您可以执行以下操作:

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;

这种特殊情况可以进一步简化为普通的SQL函数:

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;

答案 1 :(得分:2)

您也可以使用PostgreSQL数组 - 它类似于Oracle的集合:

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)

但在你的情况下,克雷格林格的建议是完美的,应该更好。

答案 2 :(得分:1)

在PostgreSQL 10中,您可以使用 array_agg

select * from unnest(v_ids) where ...

您将拥有数组,可以使用不需要来选择它:

    var authContext = new AuthenticationContext(config);

        var isCallback = authContext.isCallback(window.location.hash);
        authContext.handleWindowCallback();

        if (isCallback && !authContext.getLoginError()) {
            window.location = authContext._getItem(authContext.CONSTANTS.STORAGE.LOGIN_REQUEST);
        }

        var user = authContext.getCachedUser();
        if (!user) {
            authContext.login();
        }

答案 3 :(得分:0)

-- Fetch the next 5 rows in the cursor_01:
FETCH FORWARD 5 FROM cursor_01;

PostgreSQL 10以上版本有效。

https://www.postgresql.org/docs/10/sql-fetch.html