문제

I have a table with this structure

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

there is another table with this structure

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

Imagine that Column Cust_No from Table1 has data.By this I mean there are some data for Cust_No in this field. I need to Update other columns of the table based on this column and column Cust_No of Table2 and find First_Name and Last_Name for each Customer Number. What I have written so far is this :

-- 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;

What I'm doing in this query is that First of all, I'm using a Merge statement to find customer's first and last name and update column Is_Checked to 1 when Customers have first and last name. In the second part I'm updating columns that does not match to any records in Table2.

I want to know wether there are better ways to write this query in terms of performance.

도움이 되었습니까?

해결책

If I understand what you're doing there (which I may not be 100% .. ) .. it appears you're trying to update REQUEST table, using the other VMI_DIMCUSTOMER table as "input" .. but only if records exist. If there are not records in VMI_DIMCUSTOMER table, for a given record in REQUEST, you want to flag the record in REQUEST with your "customer not found" message, and set first/last names to '--' and error code to 2 and is_checked to 0.

If you find the record, instead the names are populated, is_checked is set to 1, and error code is set to 0.

This can be done in a single sql .. I've used this method before. The basic idea is, forget the update, merge, etc .. and just write a SELECT statement that returns the END STATE that you really want.

If I understood you properly . you want something like this:

  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
  /

By doing an outer join, we'll include ALL rows in REQUEST, even if we don't find them in VMI_DIMCUSTOMER. we check if the CUST_FIRST_NAME in VMI_DIMCUSTOMER is null (you can instead check for a CUST_NO column if you have one .. but you showed the table structure for something different than what you're using .. so wasn't sure).

And use CASE to pull/set whatever value you want/need for each row, depending on if you find it in VMI_DIMCUSTOMER or not.

Once you have that "final result set" query ironed out (and it's easy to test run to verify .. ;) )

Plugging it into a merge is simple ... first, add rowid to the query to make it easier to pick out the row .. and then plug into a simple 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, and it'll set the flags depending on if it found them in the other table or not.. ;)

If it doesn't quite work as you need, please clarify in more detail your requirements .. it shouldn't be hard to modify the merge to fit your needs.

다른 팁

Assuming your second update needs to only work on the records that were just updated in the merge statement, the following should do the trick:

MERGE INTO request tgt
  USING vmi_dimcustomer src
    ON (tgt.cust_no = src.customer_num AND tgt.is_checked IS NULL)
WHEN MATCHED THEN
  UPDATE SET tgt.first_name = CASE WHEN src.cust_first_name IS NULL THEN '--' ELSE src.cust_first_name END,
             tgt.last_name = CASE WHEN src.cust_first_name IS NULL THEN '--' ELSE src.cust_last_name END,
             tgt.error_code = CASE WHEN src.cust_first_name IS NULL THEN 2 ELSE 0 END,
             tgt.error_desc = CASE WHEN src.cust_first_name IS NULL THEN 'Customer Not Found' ELSE NULL END,
             tgt.is_checked = CASE WHEN src.cust_first_name IS NULL THEN 0 ELSE 1 END;

COMMIT;

This works by checking the results of the join between the source and target tables and using the relevant values for the columns being updated, depending on whether the first_name column in vmi_dimcustomer is null or not.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 dba.stackexchange
scroll top