PL / SQL中的refcursor概念

时间:2014-11-15 04:39:08

标签: plsql oracle-sqldeveloper plsqldeveloper toad

您只是想知道refcursor。我创建了一个包如下 - 创建或替换包装体APPS.emp_pay_pkg IS

PROCEDURE emp_pay_period_proc(
                               p_user_id in varchar2,
                               p_pay_period_date out sys_refcursor,
                               p_success out varchar2)
   IS
      idx      PLS_INTEGER := 0;

      l_pay_start_period date;
    l_pay_end_period date;

      --Curso c_ap is fetching  the pay period details.


   BEGIN
      idx := 0;
      arempty (1) := '';

      OPEN p_pay_period_date for 
         SELECT PTP.START_DATE PAY_PERIOD_START_DATE,
           PTP.END_DATE PAY_PERIOD_END_DATE

        FROM Pay_period ptp
where tso_td=p_user_id

    GROUP BY  PTP.START_DATE,PTP.END_DATE;      

      FETCH p_pay_period_date
           INTO l_pay_start_period,l_pay_end_period;


   EXCEPTION
      WHEN OTHERS
      THEN
         DBMS_OUTPUT.put_line (SQLERRM);

         p_success := 'Records get error out in Array ';
   END;
END emp_pay_pkg;
/

now to display the data for testing i used -

DECLARE
   l_user_id        VARCHAR2 (200) := 'User_id'
   l_pay_period_date  sys_refcursor;
   L_START_DATE DATE; L_END_DATE DATE;
   l_success    VARCHAR2 (200);

BEGIN

   apps.emp_pay_period_pkg.emp_pay_period_proc (l_user_id, l_pay_period_date, l_success);
    DBMS_OUTPUT.put_line ('l_pay_period_end_date'||'|'||'l_pay_period_start_date');
    LOOP
    FETCH  l_pay_period_date 
    INTO L_START_DATE,L_END_DATE;
    EXIT WHEN l_pay_period_date%NOTFOUND;

    DBMS_OUTPUT.put_line (L_END_DATE||'|'||L_START_DATE);
    END LOOP;
    CLOSE l_pay_period_date;


   DBMS_OUTPUT.put_line ('' || l_success);
EXCEPTION
   WHEN OTHERS
   THEN
      DBMS_OUTPUT.put_line ('Error :' || SQLERRM);
END;

奇怪的部分是我使用ref游标在另一个包上使用类似的concpet但是我的同事告诉我,如果你已经取出了curdor并将其移动到包体中的变量中,那么光标变为空,所以它不应该循环并移动到匿名块中的变量。

在某处,我认为它也适用于上述包。任何人都可以清楚我的概念吗?

2 个答案:

答案 0 :(得分:1)

我不太确定我到底知道你在问什么。

游标本质上是指向可以执行以返回结果的程序的指针。它是一个仅向前的结构 - 您只能获取下一个 n 行,您无法获取以前的 n 行(除非您关闭并重新打开光标如果基础数据正在改变,那么结果集可能会有所不同)。

因为游标只是向前游标,所以在打开它的过程和该过程的调用者中从游标中获取它是非常不可能的。从语法上讲,这样做是完全有效的。但这意味着调用者永远不会看到查询返回的第一行,这很不可能是你想要的。如果要从调用者的光标中获取数据,则只能打开游标。如果要在过程中从游标中获取数据,则不应将其返回给调用者。

顺便说一句,对于任何具有“返回状态”参数的过程,几乎肯定没有意义。如果某个过程遇到无法解决的错误,则应抛出异常。调用者不应该依赖于检查返回状态,它应该捕获它可以处理的特定异常,并让其余的异常传播到调用堆栈中。不执行WHEN others的{​​{1}}异常处理程序(例如此处的异常处理程序)几乎肯定是错误,其唯一影响是隐藏错误并删除有关错误发生位置的非常有用的信息

答案 1 :(得分:0)

你的同事是对的。您的包过程不需要FETCH语句。它不需要局部变量。它不需要WHEN OTHERS异常处理程序。

如果要返回引用游标,则该过程应该只是打开游标。 例如,这就足够了:

PROCEDURE emp_pay_period_proc(p_user_id IN VARCHAR2, p_pay_period OUT SYS_REFCURSOR)
IS
BEGIN
   OPEN p_pay_period FOR

      SELECT ptp.start_date AS pay_period_start_date
           , ptp.end_date   AS pay_period_end_date
        FROM pay_period ptp
       WHERE ptp.tso_td = p_user_id
       GROUP BY ptp.start_date, ptp.end_date;

END;

如果我需要返回引用光标,我个人的偏好是使用函数而不是程序。但是考虑到问题中提供的示例,我没有看到ref光标确实是最合适的设计。