从子查询存储过程分配变量

Posted

技术标签:

【中文标题】从子查询存储过程分配变量【英文标题】:Assign variables from subquery stored procedure 【发布时间】:2014-04-15 00:47:59 【问题描述】:

我有一个返回一些输出参数的 Oracle 11.2.0 存储过程。查询的结果是使用从复杂子查询填充的 refcursor。我需要将子查询中的记录计数作为 NUMBER 输出参数返回。我在尝试将计数分配给子查询内的变量时遇到问题。有人可以让知道这在 Oracle 中是否可行,或者是否有其他方法可以做到这一点。我只需要从存储过程中返回数据和数据记录的计数。我不确定如何分配和返回计数,因为查询结果是从子查询 select 语句返回的。我正在尝试做的一个例子如下:

p_results           OUT sys_refcursor,
p_count             OUT NUMBER
OPEN p_results 
FOR 
  WITH Output1 AS
    (
    SELECT * from table1
    ),
output2 AS
    (
    SELECT * from table2 a
    left outer join Output1 b
    on a.id = b.id
     )
    Select * from output2
    p_count := select count(id) from output2   --how can I return parameters for results and count using subquery

【问题讨论】:

【参考方案1】:

你不能做你想做的事。在获取最后一行之前,Oracle 不知道游标将返回多少行。而且由于游标是只进的结构,如果您的目标是将游标返回给调用应用程序,则无法在代码中从中获取。

您可以重复查询并分两步执行此操作

SELECT COUNT(id)
  INTO p_count
  FROM (<<your query>>);

OPEN p_results
 FOR <<your query>>;

这有一个明显的缺点,即您要运行查询,计算所有结果,然后再次重新运行查询,这样效率相对较低。它有一个不太明显的缺点,count 可能与游标返回的行数不匹配,因为在您的初始 SELECT 语句开始和您的游标打开时间之间可能会提交一些其他会话,从而改变将返回的行集。

您还可以在结果的每一行中添加一个计算得到的count,即

OPEN p_results
 FOR ...
     Select o2.*, count(*) over () cnt 
       from output2 o2

这将消除两个查询返回不同行数的可能性。但是,这会使查询成本更高,因为 Oracle 需要在客户端开始从中获取结果集之前实现结果集。它可能仍然比运行相同的查询两次更有效,除非在每一行上重复的附加数值会通过增加需要通过网络传输或由客户端缓冲的数据量来产生性能问题。

一般来说,我对任何同时向调用应用程序返回计数和一组结果的设计都持怀疑态度。无论如何,调用应用程序都需要代码从游标中获取。如果它具有该代码,则非常适合计算它实际获取的行数,然后对该计算结果进行操作。您的程序应该只返回 sys_refcursor 并将计数留给客户端。

【讨论】:

是否有任何方法可以将 refcursor 存储在表变量中以获取计数并仍然从存储过程中返回 p_results? @user3397437 - 我想,您可以声明一个与您的 select 语句的投影相匹配的对象类型(更改您的代码,以便您不再执行 select *),声明该对象类型的 SQL 集合,bulk collect 将查询中的数据放入该集合类型的实例中,然后返回计数和作为查询该集合的结果的 sys_refcursor。根据所涉及的数据的大小和数量,这可能会占用大量内存,但这是可能的。不过,使用全局临时表可能会更好。

以上是关于从子查询存储过程分配变量的主要内容,如果未能解决你的问题,请参考以下文章

mysql存储过程,选择最大值并插入值并分配给变量

TSQL 何时为存储过程中的变量(和表变量)分配内存

T-SQL存储过程 - 无法将输出值分配给变量

将@@ rowcount分配给SQL Server存储过程中的变量

oracle 存储过程中查询结果无法赋值到变量,请指教

存储过程给变量赋值