在oracle中游标声明查询中使用变量
Using variables in cursor declaration query in oracle
有没有办法在游标声明中使用变量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 本身中获取日期,但是会有多余的 select 查询。有没有更好的办法 ?
根据我的评论,也许这个工作示例确实给了你一个想法:
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
然后使用该值打开游标。
您需要在循环游标之前为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;
正如有人所说,您需要将变量 V_V1 移出 FOR 循环。一旦游标打开,结果集就固定了;所以在循环内改变 V_V1 不会有任何区别。
下面的代码也避免了从你不需要做的选择中选择(并且为了简单和性能应该避免)并且命名变量有更多的意义(当我不这样做时很难做到知道代码的用途 - 但我希望你为你的 post 重新命名它们并且它们在你的实际代码中不是这样的)
此外,同样,在不知道您的代码用途的情况下,请记住 BETWEEN 是包容性的,因此 BETWEEN the_date AND the_date +1
可能包含您不想要的记录。我猜了一点,但 >= the_date AND < the_date + 1
可能是正确的子句。
作为最佳实践建议,我还可以建议,如果您还没有将您的过程放入包中,那么您应该这样做,并且代码中的注释应该只用于 为什么代码是它是这样的而不是它是什么。即 cursor declaration 的注释对代码的可读性没有好处。根据循环中的处理,您还应该考虑使用 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;
有没有办法在游标声明中使用变量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 本身中获取日期,但是会有多余的 select 查询。有没有更好的办法 ?
根据我的评论,也许这个工作示例确实给了你一个想法:
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
然后使用该值打开游标。
您需要在循环游标之前为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;
正如有人所说,您需要将变量 V_V1 移出 FOR 循环。一旦游标打开,结果集就固定了;所以在循环内改变 V_V1 不会有任何区别。
下面的代码也避免了从你不需要做的选择中选择(并且为了简单和性能应该避免)并且命名变量有更多的意义(当我不这样做时很难做到知道代码的用途 - 但我希望你为你的 post 重新命名它们并且它们在你的实际代码中不是这样的)
此外,同样,在不知道您的代码用途的情况下,请记住 BETWEEN 是包容性的,因此 BETWEEN the_date AND the_date +1
可能包含您不想要的记录。我猜了一点,但 >= the_date AND < the_date + 1
可能是正确的子句。
作为最佳实践建议,我还可以建议,如果您还没有将您的过程放入包中,那么您应该这样做,并且代码中的注释应该只用于 为什么代码是它是这样的而不是它是什么。即 cursor declaration 的注释对代码的可读性没有好处。根据循环中的处理,您还应该考虑使用 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;