2017-04-14 50 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