Performance

比使用 Merge 語句更新表的列更好的方法

  • September 9, 2019

我有一個這種結構的表

Table1(Cust_No    Varchar2(50),
      First_Name Varchar2(50),
      Last_Name  Varchar2(50),
      Error_Code Number(1)   ,
      Error_Desc Varchar2(50))

還有另一個具有這種結構的表

Table2(Cust_No            Varchar2(50),
      Customer_FirstName Varchar2(50),
      Customer_LastName  Varchar2(50)
      )

想像一下 Column Cust_NofromTable1有數據。我的意思是這個欄位中有一些 Cust_No 的數據。我需要Update根據該列和該列的表的其他列,Cust_No並為每個客戶編號Table2查找。First_Name and Last_Name到目前為止我寫的是這樣的:

-- FIND CUSTOMER'S FIRST AND LAST NAME

  MERGE INTO (SELECT * FROM REQUEST R WHERE R.IS_CHECKED IS NULL) R
  USING VMI_DIMCUSTOMER V
  ON (V.CUSTOMER_NUM = R.CUST_NO)
   WHEN MATCHED THEN
   UPDATE
     SET R.FIRST_NAME = V.CUST_FIRST_NAME,
         R.LAST_NAME  = V.CUST_LAST_NAME,
         R.ERROR_CODE = 0,
         R.IS_CHECKED = 1;

           COMMIT;

  -- CUSTOMERS NOT FOUND


 UPDATE /*+ PARALLEL(4) */ REQUEST T
    SET T.FIRST_NAME = '--',
        T.LAST_NAME  = '--',
        T.ERROR_CODE = 2,
        T.ERROR_DESC = 'Customer Not Found',
        T.IS_CHECKED = 0
     WHERE T.FIRST_NAME IS NULL;

       COMMIT;

我在這個查詢中所做的是首先,我使用Merge語句來查找客戶的名字和姓氏,並Is_Checked在客戶有名字和姓氏時將列更新為 1。在第二部分中,我將更新與Table2.

我想知道在性能方面是否有更好的方法來編寫這個查詢。

如果我明白你在那裡做什麼(我可能不是 100% .. ).. 看來你正在嘗試更新 REQUEST 表,使用另一個 VMI_DIMCUSTOMER 表作為“輸入”.. 但前提是存在記錄。如果 VMI_DIMCUSTOMER 表中沒有記錄,對於 REQUEST 中的給定記錄,您希望使用“找不到客戶”消息標記 REQUEST 中的記錄,並將名字/姓氏設置為 ‘–’ 並將錯誤程式碼設置為 2 和is_checked 為 0。

如果找到記錄,而不是填充名稱,is_checked 設置為 1,錯誤程式碼設置為 0。

這可以在單個 sql 中完成。我以前使用過這種方法。基本思想是,忘記更新、合併等,只需編寫一個返回您真正想要的 END STATE 的 SELECT 語句。

如果我理解正確的話。你想要這樣的東西:

 SELECT CASE WHEN v.cust_first_name IS NULL
             THEN '--' ELSE r.first_name END   first_name,
        CASE WHEN v.cust_first_name IS NULL
             THEN '--' ELSE r.last_name END    last_name,
        CASE WHEN v.cust_first_name IS NULL
             THEN 2 ELSE 0 END                 error_code,
        CASE WHEN v.cust_first_name IS NULL
             THEN 0 ELSE 1 END                 is_checked,
        CASE WHEN v.cust_first_name IS NULL
             THEN 'Customer Not Found' ELSE NULL  END     error_desc
   FROM request           r
       LEFT OUTER JOIN
          vmi_dimcustomer   v
       ON v.cust_first_name = r.first_name
       and v.cust_last_name = r.last_name
  WHERE r.error_code = 0
    AND r.is_checked = 1
 /

通過執行外連接,我們將在 REQUEST 中包含所有行,即使我們在 VMI_DIMCUSTOMER 中找不到它們。我們檢查 VMI_DIMCUSTOMER 中的 CUST_FIRST_NAME 是否為空(如果您有 CUST_NO 列,則可以改為檢查 .. 但您顯示的表結構與您使用的不同.. 所以不確定)。

並使用 CASE 為每一行提取/設置您想要/需要的任何值,具體取決於您是否在 VMI_DIMCUSTOMER 中找到它。

一旦你完成了“最終結果集”查詢(並且很容易測試執行以驗證.. ;))

將其插入合併很簡單……首先,將 rowid 添加到查詢中,以便更容易挑選出行……然後插入一個簡單的 MERGE :

 MERGE INTO request  old
    USING (
          SELECT r.rowid  rid,
                 CASE WHEN v.cust_first_name IS NULL
                      THEN '--' ELSE r.first_name END   first_name,
                 CASE WHEN v.cust_first_name IS NULL
                      THEN '--' ELSE r.last_name END    last_name,
                 CASE WHEN v.cust_first_name IS NULL
                      THEN 2 ELSE 0 END                 error_code,
                 CASE WHEN v.cust_first_name IS NULL
                      THEN 0 ELSE 1 END                 is_checked,
                 CASE WHEN v.cust_first_name IS NULL
                      THEN 'Customer Not Found' ELSE NULL  END     error_desc
            FROM request           r
                LEFT OUTER JOIN
                   vmi_dimcustomer   v
                ON v.cust_first_name = r.first_name
                and v.cust_last_name = r.last_name
           WHERE r.error_code = 0
             AND r.is_checked = 1
          )  new
    ON ( new.rid = old.rowid )
    WHEN MATCHED THEN
       UPDATE
          SET old.first_name = new.first_name,
              old.last_name = new.last_name,
              old.error_code = new.error_code,
              old.is_checked = new.is_checked,
              old.error_desc = new.error_desc
 /

viola .. 1 sql,它會根據是否在另一個表中找到它們來設置標誌.. ;)

如果它不能完全按照您的需要工作,請更詳細地說明您的要求.. 修改合併以滿足您的需要應該不難。

引用自:https://dba.stackexchange.com/questions/246917