2010-02-18 589 views
8

這裏是我的光標:如何查找Oracle PL/SQL遊標中的記錄數量?

CURSOR C1 IS SELECT * FROM MY_TABLE WHERE SALARY < 50000 FOR UPDATE; 

我立即以鎖定這些記錄我的過程期間打開遊標。

我想提出一個應用程序錯誤,如果我的光標有2條記錄。使用C1%ROWCOUNT屬性失敗,因爲它只計算迄今爲止已獲取的數量。

這個用例的最佳模式是什麼?我是否需要創建一個虛擬的MY_TABLE%ROWTYPE變量,然後通過光標循環來獲取它們並保留一個計數,或者有更簡單的方法嗎?如果這是做到這一點的方法,那麼將獲取我遊標中的所有行隱式關閉它,從而解鎖這些行,或者保持打開狀態直到我明確地關閉它,即使我已經將它們全部提取出來了。

我需要確保遊標保持打開狀態,以便執行超出此計數的各種其他任務。

回答

6

NB:我剛纔重讀你的問題..你要失敗的。如果只有1個記錄.. 我會後在某一時刻有新的更新..

,讓我們開始在這裏..

的Oracle®數據庫PL/SQL用戶指南和參考 10g第2版(10.2) 型號B14261-01 reference

所有行在你打開遊標時重新鎖定,而不是在取出遊標時鎖定。當您提交或回滾事務時,這些行將被解鎖。由於行不再被鎖定,所以在提交後無法從FOR UPDATE遊標讀取。

所以你不需要擔心記錄解鎖。

所以試試這個..

declare 
    CURSOR mytable_cur IS SELECT * FROM MY_TABLE WHERE SALARY < 50000 FOR UPDATE; 

    TYPE mytable_tt IS TABLE OF mytable_cur %ROWTYPE 
    INDEX BY PLS_INTEGER; 

    l_my_table_recs mytable_tt; 
    l_totalcount NUMBER; 
begin 

    OPEN mytable_cur ; 
    l_totalcount := 0; 

    LOOP 
     FETCH mytable_cur 
     BULK COLLECT INTO l_my_table_recs LIMIT 100; 

     l_totalcount := l_totalcount + NVL(l_my_table_recs.COUNT,0); 

     --this is the check for only 1 row.. 
     EXIT WHEN l_totalcount < 2; 

     FOR indx IN 1 .. l_my_table_recs.COUNT 
     LOOP 
     --process each record.. via l_my_table_recs (indx) 

     END LOOP; 

     EXIT WHEN mytable_cur%NOTFOUND; 
    END LOOP; 

    CLOSE mytable_cur ; 
end; 

ALTERNATE ANSWER 我看了你的答案向後啓動,以爲你想退出,如果有更多的則1排..不是正好有一個。所以這是我以前的答案。

2個簡單的方法來檢查只有1條記錄。

選項1 - 顯式去抓取

declare 
    CURSOR C1 IS SELECT * FROM MY_TABLE WHERE SALARY < 50000 FOR UPDATE; 
    l_my_table_rec C1%rowtype; 
    l_my_table_rec2 C1%rowtype; 
begin 

    open C1; 
    fetch c1 into l_my_table_rec; 

    if c1%NOTFOUND then 
     --no data found 
    end if; 

    fetch c1 into l_my_table_rec2; 
    if c1%FOUND THEN 
     --i have more then 1 row 
    end if; 
    close c1; 

    -- processing logic 

end; 

我希望你的想法。

選擇2 - 異常捕獲

declare 
    CURSOR C1 IS SELECT * FROM MY_TABLE WHERE SALARY < 50000 FOR UPDATE; 
    l_my_table_rec C1%rowtype; 
begin 
    begin 
    select * 
     from my_table 
     into l_my_table_rec 
    where salary < 50000 
     for update; 
    exception 
    when too_many_rows then 
     -- handle the exception where more than one row is returned 
    when no_data_found then 
     -- handle the exception where no rows are returned 
    when others then raise; 
    end; 

    -- processing logic 
end; 

此外 記住:用顯式遊標..你可以%鍵入您的變量關閉光標記錄而不是原始表。

當您在查詢中加入時,這特別有用。

此外,rememebr您可以用

UPDATE table_name 
SET set_clause 
WHERE CURRENT OF cursor_name; 

類型語句更新表中的行,但我認爲如果你還沒有「獲取」第二行只會工作..


有關遊標FOR循環一些更多的信息.​​.嘗試 Here

+0

感謝全面的答案。我希望有可能是一個更簡單的方式來獲得的光標記錄的計數而不實際獲取的所有數據,但我更喜歡這種解決方案在出臺保存點。將一堆記錄讀入我沒有用的變量中感覺很笨拙(這實際上只是一個鎖,我需要知道我鎖定了多少記錄)。我的使用案例是我需要刪除一個記錄,但必須總是剩下一個;在我確認2存在於我的光標後,我發出一個單獨的刪除來查明我想刪除的特定記錄。 – 2010-02-19 14:36:38

+0

好吧..也許你應該嘗試反向..和只是一個直上「重複」的行刪除。如果他們不存在..然後什麼也沒有發生。如果他們這樣做,你留下1? ..即DELETE FROM my_table WHERE(這裏只選擇重複的行); – ShoeLace 2010-02-22 22:54:18

0

在遍歷遊標之前創建保存點,然後在發現有2條記錄返回時使用部分回滾。

0

您就可以開始交易,並檢查是否SELECT COUNT(*)MY_TABLE WHERE SALARY < 50000大於1

1

如果你正在尋找失敗whenver你有超過1個返回行,試試這個:

declare 
    l_my_table_rec my_table%rowtype; 
begin 
    begin 
    select * 
     from my_table 
     into l_my_table_rec 
    where salary < 50000 
     for update; 
    exception 
    when too_many_rows then 
     -- handle the exception where more than one row is returned 
    when no_data_found then 
     -- handle the exception where no rows are returned 
    when others then raise; 
    end; 

    -- processing logic 
end; 
1

如果這是要做到這一點,將 獲取所有行我的光標 隱式關閉它,從而解鎖 那些行

無論何時(或是否)您關閉光標,鎖都將存在於事務處理期間(即直到您執行提交或回滾)。

我會去

declare 
    CURSOR C1 IS SELECT * FROM MY_TABLE WHERE SALARY < 50000 FOR UPDATE;; 
    v_1 c1%rowtype; 
    v_cnt number; 
begin 
    open c_1; 
    select count(*) into v_cnt FROM MY_TABLE WHERE SALARY < 50000 and rownum < 3; 
    if v_cnt < 2 then 
    raise_application_error(-20001,'...'); 
    end if; 
    --other processing 
    close c_1; 
end; 

有一個很小的機會,之間的時間打開遊標(鎖定行)和​​SELECT COUNT,有人插入一個或多個行到一個表薪金低於50000.在這種情況下,應用程序錯誤會被提高,但遊標只會處理打開遊標時出現的行。如果這是一個擔心,最後再對c_1%rowcount進行檢查,如果遇到問題,則需要回滾到保存點。