2012-02-02 33 views
3

我做了一個光標,以便在數據庫合併/更新記錄的數據庫誰能幫助我與我的PL/SQL腳本來更新/合併在

我在想,如果它是正確的,或者如果任何人有任何建議爲了改善查詢。

DECLARE 
CURSOR c_itemloc 
IS 
SELECT 
    item , 
    loc , 
    loc_type , 
    source_method , 
    primary_supp , 
    source_wh 
FROM 
    (SELECT dc_vert.item , 
    dc_vert.loc , 
    dc_vert.loc_type , 
    dc_vert.source_method , 
    dc_vert.primary_supp , 
    w.primary_vwh source_wh --,dc_vert.source_wh 
    , 
    dc_vert.actie , 
    MAX(dc_vert.actie) over (PARTITION BY dc_vert.item, dc_vert.loc) actie_max , 
    COUNT(dc_vert.primary_supp) over (PARTITION BY dc_vert.item, dc_vert.loc) primary_count 
    FROM dc_item_loc_pim_lms dc_vert , 
    item_supplier isu , 
    store sto , 
    wh w 
    WHERE dc_vert.primary_supp IS NOT NULL 
    AND isu.item     = dc_vert.item 
    AND dc_vert.primary_supp  = isu.supplier 
    AND W.WH      = dc_vert.source_wh 
    AND sto.store     = dc_vert.loc 
    AND ISU.SUPP_DISCONTINUE_DATE >= SYSDATE 
) 
    WHERE actie  = actie_max 
    AND primary_count = 1; 
    l_item item_loc.item%TYPE; 
    l_loc item_loc.loc%TYPE; 
    loc_type item_loc.loc_type%TYPE; 
    l_source_method item_loc.source_method%TYPE; 
    l_primary_supp item_loc.primary_supp%TYPE; 
    l_source_wh item_loc.source_wh%TYPE; 

    i  NUMBER; 
    l_commit VARCHAR2(1) := 'Y'; 
    BEGIN 
    i    :=0; 
    FOR r_itemloc IN c_itemloc 
    LOOP 
    i := i+1; 
    UPDATE item_loc il 
    SET 
    il.source_method  = r_itemloc.source_method ,  -- 'S' 
    il.loc_type    = r_itemloc.loc_type ,  -- 'S' 
    il.primary_supp   = r_itemloc.primary_supp , 
    il.source_wh   = r_itemloc.source_wh , 
    il.last_update_datetime = SYSDATE 
    WHERE item     = r_itemloc.item 
    AND loc     = r_itemloc.loc; 
    IF l_commit     = 'Y' AND mod(i, 1000) = 0 THEN 
    COMMIT ; 
    END IF; 
    END LOOP; 
    EXCEPTION 
    WHEN OTHERS THEN 
    dbms_output.put_line('SOMETHING WENT WRONG'); 
    END; 
+0

沒有考試的時候我還沒有看到任何錯誤,但在此之前我更新我雖然我需要它在執行查詢之前重新檢查。 – Eve 2012-02-02 17:20:09

+0

我個人推薦使用@來聲明變量,當別人讀取代碼時,它也使得它更具可讀性,但如果您想更改現有代碼,則取決於您。Eve我沒看到這是Oracle。 。忽略我的代碼示例..對不起,我錯了 – MethodMan 2012-02-02 17:22:12

回答

4

1)你用無意義的錯誤代替了一個有意義的錯誤。另外,如果您還沒有set output on,則錯誤將完全丟失。最好的辦法是簡單地移除異常塊。如果你不能這樣做,你應該至少將SQLERRMDBMS_UTILITY.FORMAT_ERROR_BACKTRACE轉儲到DBMS_OUTPUT。爲了很好地捕獲和記錄錯誤,您需要將異常詳細信息傳遞給一個單獨的過程,該過程將使用自治事務將這些詳細信息寫入表中。儘管如此,即使在這種情況下,您最好在錄製後重新提升錯誤。

2)在大多數情況下,承諾每X記錄是一個不好的做法。如果這些記錄全部更新,那麼它們應該是同一交易的一部分。

3)您可以使用UPDATEMERGE在單個語句中執行此操作。通常這是首選,因爲它避免了額外的上下文切換。就個人而言,我喜歡MERGE在這樣的場景:

MERGE INTO item_loc il 
USING  (SELECT item, 
        loc, 
        loc_type, 
        source_method, 
        primary_supp, 
        source_wh 
      FROM (SELECT dc_vert.item, 
          dc_vert.loc, 
          dc_vert.loc_type, 
          dc_vert.source_method, 
          dc_vert.primary_supp, 
          w.primary_vwh source_wh, 
          dc_vert.actie, 
          MAX(dc_vert.actie) OVER (PARTITION BY dc_vert.item, dc_vert.loc) actie_max, 
          COUNT(dc_vert.primary_supp) OVER (PARTITION BY dc_vert.item, dc_vert.loc) primary_count 
        FROM dc_item_loc_pim_lms dc_vert, 
          item_supplier isu, 
          store sto, 
          wh w 
        WHERE dc_vert.primary_supp IS NOT NULL 
         AND isu.item = dc_vert.item 
         AND dc_vert.primary_supp = isu.supplier 
         AND w.wh = dc_vert.source_wh 
         AND sto.store = dc_vert.loc 
         AND isu.supp_discontinue_date >= SYSDATE) 
      WHERE actie = actie_max AND primary_count = 1) itemloc 
ON   (il.item = itemloc.item AND il.loc = itemloc.loc) 
WHEN MATCHED THEN 
    UPDATE SET 
     il.source_method   = itemloc.source_method, 
     il.loc_type    = itemloc.loc_type, 
     il.primary_supp   = itemloc.primary_supp, 
     il.source_wh    = itemloc.source_wh, 
     il.last_update_datetime = SYSDATE; 
7

假設代碼確實在功能上你想要的...

1)刪除異常處理程序。捕獲未知的異常是沒有好處的,除非您正在執行類似於登錄和重新拋出它的操作。僅在調用dbms_output時捕獲異常不僅隱藏了異常詳細信息和需要調試異常的堆棧跟蹤,而且如果調用者不想從緩衝區dbms_output中寫入,則可能會完全隱藏異常。

2)在循環中提交通常是一個壞主意。最重要的是,如果你的會話在中途死亡會發生什麼?稍後重新啓動代碼時,您將無法恢復部分提交的更新。您必須重新更新您之前更新的所有行以及您承諾的可能會產生下游影響的更新。並且在一個循環中進行提交會減慢代碼的速度,因爲沒有真正的原因。 3)如果你所要做的只是更新一個表,最有效的方法是編寫一個單一的UPDATE語句,它一次更新所有的行,而不是遍歷遊標並做大量的單向查詢,行更新。可能還有其他一些原因來支持遊標(例如,它可能會使代碼更易於其他開發人員理解),但從性能的角度來看,如果您可以在SQL中執行此操作,那麼SQL將是最有效的方法。

0

我會建議你使用現代聯接語法

FROM 
    dc_item_loc_pim_lms dc_vert 
    INNER JOIN item_supplier isu 
     ON dc_vert.item = isu.item AND 
      dc_vert.primary_supp = isu.supplier 
    INNER JOIN store sto 
     ON dc_vert.loc = sto.store 
    INNER JOIN wh w 
     ON dc_vert.source_wh = w.wh 
WHERE 
    dc_vert.primary_supp IS NOT NULL AND 
    isu.supp_discontinue_date >= SYSDATE