【问题标题】:PostgreSQL equivalent of Oracle "bulk collect"PostgreSQL 相当于 Oracle“批量收集”
【发布时间】:2013-04-29 22:22:18
【问题描述】:

在 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;

谢谢

【问题讨论】:

  • “批量收集到”有什么作用?我根本不熟悉那种语法。
  • 看起来是性能优化提示。 dba-oracle.com/t_oracle_bulk_collect.htm 。它似乎将行块提取到临时内存表中。
  • 您可能还想查看cursors 以获得类似于bulkcopy 的内容。

标签: postgresql plpgsql


【解决方案1】:

在 PostgreSQL 10 中,您可以使用 array_agg

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

    --use v_ids...

end;

您将拥有数组,并且可以使用 unnest 从中进行选择:

select * from unnest(v_ids) where ...

【讨论】:

    【解决方案2】:

    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;
    

    【讨论】:

    • 克雷格·林格,感谢您的回复。这就是所有需要。是否可以为像(执行 sql_command)这样的动态语句更改(从 tb_person 中选择 *)。我试过了,但没有成功。
    • @Leandro 是的,仅在 PL/PgSQL 中。使用RETURN QUERY EXECUTE。如果您仍然遇到问题,请发布一个新的详细问题,其中包含您的代码全文、确切的错误消息等,并链接回此问题以获取上下文。
    【解决方案3】:

    您也可以使用 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)
    

    但在你的情况下,克雷格·林格的提议是完美的,应该更可取。

    【讨论】:

      【解决方案4】:
      -- 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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-07-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多