我正在使用Oracle DB和SQL Developer尝试这个简单的过程:
CREATE OR REPLACE PROCEDURE test_prod AS
query_str VARCHAR2(200);
i INTEGER := 0;
TYPE cur IS REF CURSOR;
my_cur cur;
BEGIN
query_str := 'SELECT * FROM table WHERE ROWNUM<=1000';
OPEN my_cur FOR query_str;
DBMS_OUTPUT.PUT_LINE('start');
LOOP
i := i + 1;
DBMS_OUTPUT.PUT_LINE('i: ' || i);
END loop;
DBMS_OUTPUT.PUT_LINE('COUNT: ' || i);
CLOSE my_cur;
END;
&#39; i&#39;的最后一个值是3014(预期的一个是1000)和最后一个&#39; put_line&#39;没有显示。
此外,如果我尝试仅在循环中放入增量然后显示最终值,则该过程不会结束。
任何人都可以建议我问题出在哪里?
由于
答案 0 :(得分:1)
我不想进入特定的游标参数(你可以在Internet / Oracle网站上找到很多教程)。只是为了向你展示你的存储过程的一些小编辑来制作你想要的东西(我不这样做这个提议的程序是最好的方法):
create or replace PROCEDURE TEST_PROD IS
query_str VARCHAR2(200);
i BINARY_INTEGER := 0;
TYPE cur IS REF CURSOR;
my_cur cur;
TYPE rek IS TABLE OF table%ROWTYPE INDEX BY BINARY_INTEGER;
my_rek rek;
BEGIN
query_str := 'SELECT * FROM table WHERE ROWNUM<=1000';
OPEN my_cur FOR query_str;
DBMS_OUTPUT.PUT_LINE('start');
LOOP
i := i + 1;
DBMS_OUTPUT.PUT_LINE('i: ' || i);
FETCH my_cur INTO my_rek(i) ;
EXIT WHEN my_cur%NOTFOUND;
END loop;
DBMS_OUTPUT.PUT_LINE('COUNT: ' || i);
CLOSE my_cur;
END;
答案 1 :(得分:1)
Aleksej在可能的情况下使用隐式游标有一个很好的答案 - 隐式游标自动关闭并且简洁易读。对于您的示例,隐式游标是一种推荐的方法。
我将在这里添加一些与etsa的回答有关的其他示例 仅用于在原始帖子中使用显式游标的替代方法。
如果您想停止循环播放,则LOOP
上需要退出条件。
明确您可以在计数器达到特定值时退出,或者当您的CURSOR已经退出时,或者您喜欢的任何其他条件时退出。
带有显式游标的示例1 - 当游标用完数据时退出循环:
创建一个测试表:
CREATE TABLE MY_TABLE(MY_TABLE_DATA NUMBER);
加载它:
INSERT INTO MY_TABLE SELECT ROWNUM FROM ALL_OBJECTS WHERE ROWNUM < 100;
然后创建您的程序:
CREATE OR REPLACE PROCEDURE TEST_PROD IS
QUERY_STR VARCHAR2(200);
I INTEGER := 0;
TYPE CUR IS REF CURSOR;
V_MY_TABLE_DATA MY_TABLE%ROWTYPE;
MY_CUR CUR;
BEGIN
QUERY_STR := 'SELECT * FROM MY_TABLE WHERE ROWNUM<=5';
OPEN MY_CUR FOR QUERY_STR;
DBMS_OUTPUT.PUT_LINE('START');
LOOP
FETCH MY_CUR INTO V_MY_TABLE_DATA;
EXIT WHEN MY_CUR%NOTFOUND;
I := I + 1;
DBMS_OUTPUT.PUT_LINE('I: ' || I);
DBMS_OUTPUT.PUT_LINE('MY-TABLE-DATA: ' || V_MY_TABLE_DATA.MY_TABLE_DATA);
END LOOP;
DBMS_OUTPUT.PUT_LINE('COUNT: ' || I);
CLOSE MY_CUR;
END;
/
试一试:
BEGIN
TEST_PROD();
END;
/
START
I: 1
MY-TABLE-DATA: 1
I: 2
MY-TABLE-DATA: 2
I: 3
MY-TABLE-DATA: 3
I: 4
MY-TABLE-DATA: 4
I: 5
MY-TABLE-DATA: 5
COUNT: 5
或者您可以根据I
停止循环:
CREATE OR REPLACE PROCEDURE TEST_PROD IS
QUERY_STR VARCHAR2(200);
I INTEGER := 0;
TYPE CUR IS REF CURSOR;
V_MY_TABLE_DATA MY_TABLE%ROWTYPE;
MY_CUR CUR;
BEGIN
QUERY_STR := 'SELECT * FROM MY_TABLE WHERE ROWNUM<=10';
OPEN MY_CUR FOR QUERY_STR;
DBMS_OUTPUT.PUT_LINE('START');
LOOP
IF I >= 3 THEN
EXIT;
END IF;
FETCH MY_CUR INTO V_MY_TABLE_DATA;
I := I + 1;
DBMS_OUTPUT.PUT_LINE('I: ' || I);
DBMS_OUTPUT.PUT_LINE('MY-TABLE-DATA: ' || V_MY_TABLE_DATA.MY_TABLE_DATA);
END LOOP;
DBMS_OUTPUT.PUT_LINE('COUNT: ' || I);
CLOSE MY_CUR;
END;
/
BEGIN
TEST_PROD();
END;
/
START
I: 1
MY-TABLE-DATA: 661
I: 2
MY-TABLE-DATA: 662
I: 3
MY-TABLE-DATA: 663
COUNT: 3
答案 2 :(得分:0)
这里的主要问题是你的循环没有结束条件:你的循环与你打开的光标无关,所以它会永远循环,无论光标的行数是多少。
如果您需要循环选择查询的结果,这是一种简单的方法:
create or replace procedure testLoop is
begin
for rec in (
select level as val
from dual
connect by level <= 5
)
loop
dbms_output.put_line(rec.val);
end loop;
end;
电话:
SQL> exec testLoop;
1
2
3
4
5