2017-04-14 48 views
-1

我试图使用Oracle数据库和SQL开发这个简单的程序:PL-SQL过程问题

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; 

为“i”是3014(所预期的是1000)的最后一个值和最后一个“PUT_LINE '不显示。此外,如果我试着只在循环中放入增量,然后显示最终值,那么过程并不会结束。

任何人都可以建议我问题在哪里?

感谢

+2

你的循环没有结束条件。我无法想象它是如何停在3014。我猜测你想用光标做点什么。这通常就是为什么设立这样一个循环。 –

+0

btw你不需要'TYPE cur IS REF CURSOR;'因为Oracle已经提供'sys_refcursor'。 –

回答

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 
+0

我需要执行一个由字符串表示的查询。如果我尝试'rec in(query_string)',我得到一个错误(找到LOOP符号而不是& - +) – Fab

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

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