2012-06-30 113 views
9

This question提出了一個非常有趣的觀點; Oracle文檔中似乎存在一個矛盾,即%NOTFOUND在提取後是否可能爲空。是嗎?獲取後可以%NOTFOUND返回null嗎?

要從11g documentation

注引用:在例6-16,如果FETCH從來沒有取出一行,那麼c1%NOTFOUND 始終是NULL和循環永遠不會退出。爲防止無限循環,請使用以下EXIT語句:EXIT當c1%NOTFOUND或 (c1%NOTFOUND IS NULL);

文檔似乎直接自相矛盾的,因爲它也說以下,這意味着,取後%NOTFOUND不能爲空。

%NOTFOUND(佔發現邏輯對面)返回:在顯式遊標後
NULL被打開,但之前的第一次提取
FALSE如果最近從顯式遊標讀取返回的行
TRUE否則

10g documentation也有類似的警告,因爲它警告說,可能會取不爲了成功執行這種行爲將要展出這不是必然,直接的矛盾。

第一次提取之前,%NOTFOUND的計算結果爲NULL。如果FETCH從不成功執行 ,EXIT WHEN條件永不爲TRUE,並且永不退出循環。爲了安全起見,您可能需要使用以下 EXIT語句:

退出時c1%NOTFOUND或c1%NOTFOUND爲NULL;

在什麼情況下可能會提取「失敗」或可能%NOTFOUND在執行提取後返回null?

回答

0

我認爲這觸發您的部分是這樣的:

如果FETCH從來沒有執行成功,在出關時的條件是不正確的,並循環永遠不會退出。

某處在過去一定有它看起來像這樣的代碼示例:

LOOP 
    FETCH c1 INTO name; 
    EXIT WHEN c1%NOTFOUND; 
    -- Do stuff 
END LOOP; 

鑑於這個代碼塊,然後將聲明環真。如果抓取從不執行(失敗),那麼%NOTFOUND將爲空。 EXIT WHEN條件不會評估爲TRUE(null評估爲false)。那麼,循環將會永遠持續下去。

+1

爲什麼會在那種情況下抓取永遠不會執行? – Ben

+0

查詢可能存在問題,它在語法上有效,但由於其他因素而失敗。 –

+0

問題的關鍵在於什麼是其他因素:-)?我無法想象代碼將通過獲取來評估'%notfound'但提取不會「有效」的單一方式。 – Ben

-1

這是容易測試的情況:

SET SERVEROUT ON; 

DECLARE 
    -- this cursor returns a single row 
    CURSOR c1 IS 
    SELECT 1 FROM dual WHERE rownum = 1; 

    -- this cursor returns no rows 
    CURSOR c2 IS 
    SELECT 1 FROM dual WHERE 1=0; 

    v1 number; 
BEGIN 
    OPEN c1; 
    FETCH c1 INTO v1; -- this returns a record 
    FETCH c1 INTO v1; -- this does not return a record 
    IF c1%NOTFOUND THEN 
    dbms_output.put_line('c1%NOTFOUND: TRUE'); 
    ELSIF c1%NOTFOUND IS NULL THEN 
    dbms_output.put_line('c1%NOTFOUND: NULL'); 
    ELSE 
    dbms_output.put_line('c1%NOTFOUND: FALSE'); 
    END IF; 
    CLOSE c1; 

    OPEN c2; 
    FETCH c2 INTO v1; -- this does not return a record 
    IF c2%NOTFOUND THEN 
    dbms_output.put_line('c2%NOTFOUND: TRUE'); 
    ELSIF c2%NOTFOUND IS NULL THEN 
    dbms_output.put_line('c2%NOTFOUND: NULL'); 
    ELSE 
    dbms_output.put_line('c2%NOTFOUND: FALSE'); 
    END IF; 
    CLOSE c2; 
END; 
/

在Oracle APEX 4所述的腳本的輸出。1是(我認爲APEX是運行Oracle 11gR2的,但你可以很容易地運行在任何版本的腳本):

c1%NOTFOUND: TRUE 
c2%NOTFOUND: TRUE 

基於此測試是讀取執行後%NOTFOUND不會是NULL。這與在%NOTFOUND屬性的初始描述中10g和11g文檔所說的相符。關於從不退出循環的注意必須來自該示例的舊版本。既然它只是一個筆記,我會說相信最初的描述並忽視筆記是安全的。

7

我能找到的情況下取回可能失敗:

declare 
    i integer; 
    cursor c is 
    select 1/0 from dual; 
begin 
    open c; 

    begin 
    fetch c 
     into i; 
    exception 
    when others then 
     dbms_output.put_line('ex'); 
    end; 

    if c%notfound is null then 
    dbms_output.put_line('null'); 
    elsif c%notfound then 
    dbms_output.put_line('true'); 
    else 
    dbms_output.put_line('false'); 
    end if; 
    close c; 

end; 

但是,這不僅使你的問題更強大,因爲它會評估爲null,既不在10g中,也不在11g中...

+1

+1因爲過於聰明:-)。文檔中的示例沒有嵌套的匿名塊... – Ben

相關問題