在oracle中使用游标声明查询中的变量

时间:2017-05-10 13:14:15

标签: oracle plsql cursor

有没有办法在游标声明sql中使用变量? 实施例 -

create or replace PROCEDURE PRD (IN_VAR  IN VARCHAR2)
IS

  V_V1 TABLE.DATE_COL%TYPE;

   /* Cursor decleration */
   CURSOR CUR_DUMMY
   IS
        SELECT COL1,COL2,COL3 
          FROM TABLE 
             WHERE DATE_COL BETWEEN V_V1 
                    AND V_V1+1;

BEGIN
   FOR REC  IN CUR_DUMMY
   LOOP

    SELECT TO_DATE(TO_CHAR(sysdate, 'DD-MON-YY') ||' '||(SELECT TO_CHAR(DAY_BEGIN,'HH24:MI:SS') FROM TABLE2),'DD-MON-YY HH24:MI:SS') INTO  V_V1 from DUAL;   

--  other stuffs
    END LOOP;
END;

此处光标无法获取所需记录。 我可以在游标声明之前的某处分配V_V1值吗? 虽然我可以在光标sql本身中获取日期但是会有冗余的选择查询。有没有更好的办法 ?

3 个答案:

答案 0 :(得分:5)

在循环游标之前,需要为V_V1赋值。此外,您需要在游标定义中定义变量(游标c_dummy(V_V1日期))并在调用游标时传递它FOR REC IN CUR_DUMMY(V_V1)

    create or replace PROCEDURE PRD (IN_VAR  IN VARCHAR2)
IS

  V_V1 TABLE.DATE_COL%TYPE;

   /* Cursor decleration */
   CURSOR CUR_DUMMY(V_V1 date)
   IS
        SELECT COL1,COL2,COL3 
          FROM TABLE 
             WHERE DATE_COL BETWEEN V_V1 
                    AND V_V1+1;

BEGIN
   SELECT TO_DATE(TO_CHAR(sysdate, 'DD-MON-YY') ||' '||(SELECT TO_CHAR(DAY_BEGIN,'HH24:MI:SS') FROM TABLE2),'DD-MON-YY HH24:MI:SS') INTO  V_V1 from DUAL;   
   FOR REC  IN CUR_DUMMY(V_V1)
   LOOP

--  do stuffs

    END LOOP;
END;

答案 1 :(得分:1)

有人已经说过你需要将变量V_V1移到FOR循环之外。打开光标后,结果集将被修复;所以在循环中更改V_V1不会有任何区别。

下面的代码也远离了从你不需要做的双重选择(并且应该避免简单和性能)并且用更多的意义命名变量(当我不知道什么时很难做到)代码是为了 - 但我希望你为你的帖子重新命名它们,并且它们在你的实际代码中不是这样的)

此外,再次不了解您的代码目的,请记住BETWEEN是包容性的,因此BETWEEN the_date AND the_date +1可能包含您不想要的记录。我猜了一下,但>= the_date AND < the_date + 1可能是正确的条款。

作为最佳实践建议,我可以建议,如果您尚未将程序放在程序包中,那么代码中的注释只应用于为什么代码是这样的不是它是什么。即,注释游标声明对您的代码的可读性没有任何好处。根据循环中的处理,您还应该考虑使用BULK COLLECT,这在其他地方有很好的记录。

CREATE OR REPLACE PROCEDURE my_procedure (in_var IN VARCHAR2)
IS    
   today_begin TABLE.DATE_COL%TYPE;
   the_day_begin TABLE2.DAY_BEGIN%TYPE;

   CURSOR todays_records( the_date DATE )
   IS
        SELECT COL1,COL2,COL3 
        FROM   TABLE 
        WHERE  DATE_COL BETWEEN the_date AND the_date + 1;

BEGIN

    SELECT DAY_BEGIN 
    INTO the_day_begin
    FROM TABLE2;

    today_begin := TO_DATE(TO_CHAR(sysdate, 'DD-MON-YY') ||' '|| TO_CHAR(the_day_begin,'HH24:MI:SS'),'DD-MON-YY HH24:MI:SS') 

    FOR rec IN todays_records( today_begin )
    LOOP
      --  other stuffs
    END LOOP;

END;

答案 2 :(得分:0)

作为对我评论的跟进,也许这个有效的例子可以给你一个想法:

DECLARE
        CURSOR c1(nId IN NUMBER) IS
               SELECT   * 
               FROM     TableA 
               WHERE    Id = nId;
BEGIN
        FOR r1 IN c1(nId => 3) LOOP
                --Do something here
                DBMS_OUTPUT.PUT_LINE('A');
        END LOOP;
END;
/

因此,在您的示例中,首先获取V_V1然后使用该值打开游标。