【问题标题】:Using variables in cursor declaration query in oracle在 oracle 的游标声明查询中使用变量
【发布时间】:2017-05-10 13:14:15
【问题描述】:

有没有办法在游标声明 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 本身中获取日期,但会有多余的选择查询。有没有更好的办法 ?

【问题讨论】:

  • 你的例子行不通。因为在将值分配给V_V1 之前,您已经执行了select。所以在你的选择中 V_V1 是 NULL。

标签: oracle plsql cursor


【解决方案1】:

你需要在循环游标之前给 V_V1 赋值。另外,需要在游标定义中定义变量(cursor c_dummy(V_V1 date)),并在调用游标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;

【讨论】:

    【解决方案2】:

    正如有人已经说过,您需要将变量 V_V1 移到 FOR 循环之外。打开游标后,结果集是固定的;所以在循环内改变 V_V1 不会有任何区别。

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

    另外,在不了解您编码目的的情况下,请记住 BETWEEN 是包容性的,因此 BETWEEN the_date AND the_date +1 可能包括您不想要的记录。我猜了一下,但>= the_date AND < the_date + 1 可能是正确的子句。

    作为最佳实践建议,我还可以建议,如果您还没有将程序放在一个包中,那么您应该这样做,并且代码中的 cmets 应该只用于为什么代码是这样的 不是 它是什么。即说 游标声明 的注释对代码的可读性没有好处。根据循环中的处理,您还应该考虑使用在其他地方详细记录的 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;
    

    【讨论】:

    • 感谢您的所有建议。是的,我为这篇文章重新命名了它们。
    【解决方案3】:

    根据我的评论,也许这个工作示例确实给了你一个想法:

    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 然后使用该值打开游标。

    【讨论】:

      猜你喜欢
      • 2020-10-10
      • 2021-05-18
      • 1970-01-01
      • 2014-03-06
      • 1970-01-01
      • 2013-10-22
      • 1970-01-01
      • 2021-10-15
      • 2011-05-14
      相关资源
      最近更新 更多