Question

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.

Was it helpful?

Solution

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.

OTHER TIPS

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with dba.stackexchange
scroll top