oracle-databasegroup-bycounthavingnvl

Use NVL, GROUP BY, HAVING COUNT to check if record are same


I have 2 tables: CUST_DETAILS with column CUST_REF_ID and CUST_MERGE with columns NEW_CUST_REF_ID and OLD_CUST_REF_ID, below script will check if both columns in CUST_MERGE having same country id with the corresponding column in CUST_DETAILS, and return Y, else return N

SELECT
   NVL
      ((SELECT 'Y' FROM DUAL WHERE EXISITS
       (
        SELECT CTRY_ID FROM CUST_DETAILS cust_dtl
        INNER JOIN CUST_MERGE cust_merge
        ON cust_dtl.CUST_REF_ID=cust_merge.NEW_CUST_REF_ID
        AND cust_dtl.CUST_REF_ID=cust_merge.OLD_CUST_REF_ID
        GROUP BY CTRY_ID
        HAVING COUNT(CTRY_ID)>1
        )),'N') AS SAME_CTRY_ID
FROM DUAL;

The data in both tables are all having same country_id, meaning expected result is 'Y'. But 'N' returned for now, unless if I change condition from AND to OR, then it work as what expected,even the subquery also return with correct country ID

Sample Data

TABLE CUST_MERGE

 NEW_CUST_REF_ID                        OLD_CUST_REF_ID

 B5000                                   B6000

 B5000                                   A6000

TABLE CUST_DETAILS

 CUST_REF_ID                CTRY_ID  
 B5000                       US

 B6000                       US   

 A6000                       JP

When execute first line in CUST_MERGE, B5000 and B6000, return Y, as ctry_id are same (US) When execute second line in CUST_MERGE, B5000 and A6000, return N, as ctry_id are different (US,JP)


Solution

  • Use this query to get the flag:

    SQL> WITH  CUST_MERGE( NEW_CUST_REF_ID, OLD_CUST_REF_ID) AS
      2    (SELECT 'B5000', 'B6000' FROM dual UNION ALL
      3     SELECT 'A5000', 'A6000' FROM dual),
      4  CUST_DETAILS (CUST_REF_ID,CTRY_ID) AS
      5   ( SELECT 'B5000', 'US' FROM dual UNION ALL
      6     SELECT 'B6000', 'US' FROM dual UNION ALL
      7     SELECT 'A5000', 'UK' FROM dual UNION ALL
      8     SELECT 'A6000', 'JP' FROM dual)
    ----------------------------
    ----End of Data Preparation
    ----------------------------
      9  SELECT cm.new_cust_ref_id,
     10         cm.old_cust_ref_id,
     11         dc.ctry_id,
     12         dc1.ctry_id,
     13         CASE
     14           WHEN dc.ctry_id = dc1.ctry_id THEN
     15            'Y'
     16           ELSE
     17            'N'
     18         END AS flag
     19    FROM cust_merge cm
     20    JOIN cust_details dc
     21      ON cm.new_cust_ref_id = dc.cust_ref_id
     22    JOIN cust_details dc1
     23      ON cm.old_cust_ref_id = dc1.cust_ref_id;
    

    Output

    NEW_CUST_REF_ID OLD_CUST_REF_ID CTRY_ID CTRY_ID FLAG
    --------------- --------------- ------- ------- ----
    B5000           B6000           US      US      Y
    A5000           A6000           UK      JP      N
    

    The query for your tables comes out to be

    SELECT cm.new_cust_ref_id,
           cm.old_cust_ref_id,
           dc.ctry_id, 
           dc1.ctry_id,
           CASE
             WHEN dc.ctry_id = dc1.ctry_id THEN
              'Y'
             ELSE
              'N'
           END AS flag
      FROM cust_merge cm
      JOIN cust_details dc
        ON cm.new_cust_ref_id = dc.cust_ref_id
      JOIN cust_details dc1
        ON cm.old_cust_ref_id = dc1.cust_ref_id;
    

    Update: With the new data, results are as expected:

    SQL> WITH  CUST_MERGE( NEW_CUST_REF_ID, OLD_CUST_REF_ID) AS
      2    (SELECT 'B5000', 'B6000' FROM dual UNION ALL
      3     SELECT 'B5000', 'A6000' FROM dual),
      4  CUST_DETAILS (CUST_REF_ID,CTRY_ID) AS
      5   ( SELECT 'B5000', 'US' FROM dual UNION ALL
      6     SELECT 'B6000', 'US' FROM dual UNION ALL
      7     SELECT 'A6000', 'JP' FROM dual)
      8  SELECT cm.new_cust_ref_id,
      9         cm.old_cust_ref_id,
     10         dc.ctry_id,
     11         dc1.ctry_id,
     12         CASE
     13           WHEN dc.ctry_id = dc1.ctry_id THEN
     14            'Y'
     15           ELSE
     16            'N'
     17         END AS flag
     18    FROM cust_merge cm
     19    JOIN cust_details dc
     20      ON cm.new_cust_ref_id = dc.cust_ref_id
     21    JOIN cust_details dc1
     22      ON cm.old_cust_ref_id = dc1.cust_ref_id;
    

    Output:

    NEW_CUST_REF_ID OLD_CUST_REF_ID CTRY_ID CTRY_ID FLAG
    --------------- --------------- ------- ------- ----
    B5000           B6000           US      US      Y
    B5000           A6000           US      JP      N