从 PL/SQL 中的过程返回值数组

Posted

技术标签:

【中文标题】从 PL/SQL 中的过程返回值数组【英文标题】:Return an array of values from a procedure in PL/SQL 【发布时间】:2014-05-13 15:14:02 【问题描述】:

我正在寻找一种的方法。

程序有一些输入参数。基于这些输入,将创建并执行一个选择查询。在此查询的结果上,将执行更多的验证和计算。这些检查和计算的结果应该保存在一个新的数组或表格数组中,然后从过程中返回。 这个过程将在另一个 PL/SQL 脚本中多次调用,使用不同的参数来获取不同的值并对这些值进行不同的检查。

有没有办法从过程中返回一个数组?我正在寻找一种能够避免不必要的数据复制并且尽可能快的解决方案。

我已经阅读了有关临时表、PL/SQL 表、游标等的信息,但我不确定,这些是最好的方法。

【问题讨论】:

展示你的作品会很有帮助。 没有一种最好的方法来解决所有问题。这取决于您的用例是什么。 我还没有任何可以讨论的源代码。我只是想知道走哪条路。因此,如果有人能说出可能导致解决方案的 Oracle PL/SQL 概念,我会很高兴。 【参考方案1】:

函数可以返回数组吗(过程有OUT参数,函数返回东西)?没问题

CREATE OR REPLACE PACKAGE some_pkg
AS
  TYPE my_assoc_array_typ IS TABLE OF emp%rowtype INDEX BY PLS_INTEGER;

  FUNCTION return_array( p_deptno IN emp.deptno%type )
    RETURN my_assoc_array_typ;
END;

CREATE OR REPLACE PACKAGE BODY some_pkg
AS
  FUNCTION return_array( p_deptno IN emp.deptno%type )
    RETURN my_assoc_array_typ
  IS
    l_emps my_assoc_array_typ;
  BEGIN
    SELECT *
      BULK COLLECT INTO l_emps
      FROM emp
     WHERE deptno = l_deptno;

    RETURN l_emps;
  END;
END;

现在,这是最有效的方法吗?它可能是,它可能不取决于您的环境。如果有一种方法总是比替代方法更有效,Oracle 就不会费心实施替代方法。

使用关联数组(或任何 PL/SQL 集合类型)意味着您的数据存储在服务器上相对昂贵的 PGA 内存中。如果您有一个会话将几百行读入一个集合,那可能不是主要问题。另一方面,如果您有数千个会话同时尝试处理具有数百万行的集合,那么 PL/SQL 集合几乎肯定会在数据库服务器上造成瓶颈,而现在大部分服务器的 RAM 都专门用于支持这些收藏。当然,您通常可以通过将较少数量的行获取到每个集合中来解决这些问题,并且可能允许后续调用来获取后续的行集,但这意味着架构会发生变化。

相比之下,存储在临时表中的数据,就像存储在永久表中的数据一样,可能在缓冲区缓存中,也可能在任何时间点都在磁盘上。当您想要管理更大的数据量时,这使得临时表更合适。但它以性能为代价,您可能会至少对物理磁盘进行一些读取和写入操作,并且您的临时表数据将与缓冲区缓存中的其他数据竞争空间。

游标不存储数据,它只是一个指向程序(已编译的 SQL 语句)的指针,可以执行该程序以获取所需的下一行数据。

【讨论】:

感谢您的回答。似乎临时表将是适合我需要的方法。我将有很少的会话,但这些会话必须处理大量数据。我绝对想避免函数返回时在内存中复制大量数据的成本,所以使用临时表听起来很合理。我希望这样,函数内和函数外的代码访问内存的同一部分。 @user3633126 - 我不确定“在内存中复制大量数据”对您意味着什么。从一个 PL/SQL 块传递到另一个 PL/SQL 集合时,不需要复制 PL/SQL 集合(假设您在参数定义中指定了NOCOPY)。当然,需要将数据从 SQL 引擎复制到 PL/SQL 引擎,以便最初填充集合。如果您确定首先需要具体化数据,那么临时表可能是合适的,但是当您读取它时,数​​据可能不会全部都在内存中。 我不知道从函数返回时不会创建数据副本。我只是在考虑像 C++ 这样的语言,其中将指针传递给函数可以避免在堆栈上创建参数的副本。但如果这是由 PL/SQL 管理的,那很好。

以上是关于从 PL/SQL 中的过程返回值数组的主要内容,如果未能解决你的问题,请参考以下文章

PL/SQL 创建返回两个字符串值的过程

PL/SQL oracle 过程不返回任何值

PL/SQL:无法从包元素 PL/SQL 返回值

使用 JDBC 从 PL/SQL 存储函数中获取表返回值

具有布尔返回值的 pl/sql 函数的 OracleType?

是否可以从 jdbc 调用 pl/sql 函数并按名称注册返回值?