2017-08-28 94 views
0

我寫了一個用於構建報告表的軟件包。該函數的簡化代碼我測試如下:Oracle插入缺失記錄

function do_build return integer is 
    V_RESULT  PLS_INTEGER := 0; 
    cursor all_entities is 
    select e.id_number 
    from entity e 
    ; 
BEGIN 
c_count := 0; -- this variable is declared at the package level outside of this function 
for rec in all_entities LOOP 
    BEGIN 
    insert into reporting (
     select * 
     from table(get_report_data(rec.id_number)) 
    ); 
    c_count := c_count + 1; 
    if MOD(c_count, 1000) = 0 Then 
     -- record status to table 
     commit; 
    end if; 
    EXCEPTION 
    WHEN OTHERS THEN 
    -- record exception to table 
    END; 
END LOOP; 
return V_RESULT; 
END; 

一點背景:get_report_data是返回一個數據集的所有輸入實體的報告數據的功能。

當構建完成時,「報告」表中缺少大約1000萬條記錄。沒有任何異常被拋出,除了丟失的記錄外,一切看起來都是成功的(函數返回0給調用者)。

當我爲沒有記錄其報告數據的實體記錄運行get_report_data時,記錄顯示正常。其實,我可以做一個即席「插入報告(SELECT * FROM表(get_reporting_data(missing_id))」,信息將被插入。

爲什麼這些記錄被跳過/不插?我應該循環?以不同的方式沒有更好的方式來做到這一點

回答

2

您只會每1000行提交一次。你沒有提交最後一批。在END LOOP之後添加一個提交;

BEGIN 
c_count := 0; -- this variable is declared at the package level outside of this function 
for rec in all_entities LOOP 
BEGIN 
    insert into reporting (
    select * 
    from table(get_report_data(rec.id_number)) 
    ); 
    c_count := c_count + 1; 
    if MOD(c_count, 1000) = 0 Then 
    -- record status to table 
    commit; 
    end if; 
EXCEPTION 
    WHEN OTHERS THEN 
    -- record exception to table 
END; 
END LOOP; 
COMMIT; -- <-- Add this commit to pick up last few records 
return V_RESULT; 

END; 
+0

啊,對!我現在正在重新確認。謝謝。 – nrg

1

可這是一個的併發性問題。如果記錄在實體表,而你循環運行,他們將不會被處理致力於

BTW:?使用當其他人以這種方式請求麻煩時

BTW2:爲什麼不簡單使用:

INSERT INTO reporting 
SELECT rep.* 
FROM entity e 
CROSS JOIN table(get_report_data(e.id_number)) rep; 
+0

有趣。我會玩這個方法來看看它是否會產生更快的插入。我認爲它會。如果性能顯着提升,我不一定需要狀態更新。感謝您的建議。 – nrg

+0

另外,你是否在意詳細說明爲什麼使用WHEN OTHERS是不好的形式? – nrg

+0

與其他人一起,你會發現任何錯誤 - 不僅僅是你期望的錯誤。因此,與網絡連接有關的問題,數據庫正在關閉等與您正在處理的行完全無關的問題將被捕獲。 – fhossfel