Silver.Rainbow
Silver.Rainbow

Reputation: 435

Oracle SQL - Compare key and values in the same table

(reverting edit) I have a table that houses keys and values of configuration for different customer.

CustomerID    Key              Value
C1            AskPhoneNo       TRUE
C1            Website          C1Website.com
C1            Report           TRUE 
C2            AskPhoneNo       TRUE
C2            Report           FALSE
C2            AskAddress       TRUE

I need to compare the data between C1 and C2 and Show diffs like this

C1            AskPhoneNo       TRUE                C2    AskPhoneNo       TRUE
C1            Website          C1Website.com       C2      -               -
C1            Report           TRUE                C2    Report          False
C1            AskAddress       -                   C2    AskAddress   

What query can be used to get this result?

Upvotes: 0

Views: 797

Answers (5)

Thorsten Kettner
Thorsten Kettner

Reputation: 95072

In order to compare all customers with each other, first join customer to customer. Cross join all keys. Then outer join the data:

with customers as (select distinct customerid from mytable)
select
  k.key,
  c1.customerid as customerid1, m1.value as value1,
  c2.customerid as customerid2, m2.value as value2
from customers c1
join customers c2 on c2.customerid > c1.customerid
cross join (select distinct key from mytable) k
left join mytable m1 on m1.customerid = c1.customerid and m1.key = k.key
left join mytable m2 on m2.customerid = c2.customerid and m2.key = k.key
order by customerid1, customerid2, k.key;

(I suppose you have a customers table, so you can remove the WITH clause.)

Upvotes: 0

demircioglu
demircioglu

Reputation: 3465

Here is a version with parameterized Customer IDs

with 
 Cust1 as (select 'C1' as C_id from DUAL)
,Cust2 as (select 'C2' as C_id from DUAL)
select (select C_id from Cust1) ID1,
       coalesce(t1.K, t2.K) Key1,
       t1.V as Value1,
       (select C_id from Cust2) ID2,
       coalesce(t2.K, t1.K) Key2,
       t2.V as Value2
 from 
 (select * from t where id = (select C_id from Cust1)) t1
   full outer join (select * from t where id = (select C_id from Cust2)) t2 
   on t1.k = t2.k

to test I used

with 
 Cust1 as (select 'C1' as C_id from DUAL)
,Cust2 as (select 'C2' as C_id from DUAL)
,t as (
select 'C1' ID, 'AskPhoneNo' K, 'TRUE' V union
select 'C1', 'Website', 'C1Website.com' union
select 'C1', 'Report',  'TRUE' union
select 'C2', 'AskPhoneNo', 'TRUE' union
select 'C2', 'Report', 'FALSE' union
select 'C2', 'AskAddress', 'TRUE')
select (select C_id from Cust1) ID1,
       coalesce(t1.K, t2.K) Key1,
       t1.V as Value1,
       (select C_id from Cust2) ID2,
       coalesce(t2.K, t1.K) Key2,
       t2.V as Value2
 from 
 (select * from t where id = (select C_id from Cust1)) t1
   full outer join (select * from t where id = (select C_id from Cust2)) t2 
   on t1.k = t2.k

Upvotes: 0

Wei Lin
Wei Lin

Reputation: 3811

you can use full outer join + nvl

CREATE TABLE T
    ("CustomerID" varchar2(2), "Key" varchar2(10), "Value" varchar2(13));


INSERT ALL 
    INTO T ("CustomerID", "Key", "Value")
         VALUES ('C1', 'AskPhoneNo', 'TRUE')
    INTO T ("CustomerID", "Key", "Value")
         VALUES ('C1', 'Website', 'C1Website.com')
    INTO T ("CustomerID", "Key", "Value")
         VALUES ('C1', 'Report', 'TRUE')
    INTO T ("CustomerID", "Key", "Value")
         VALUES ('C2', 'AskPhoneNo', 'TRUE')
    INTO T ("CustomerID", "Key", "Value")
         VALUES ('C2', 'Report', 'FALSE')
    INTO T ("CustomerID", "Key", "Value")
         VALUES ('C2', 'AskAddress', 'TRUE')
SELECT * FROM dual;



select 
    nvl(T1."CustomerID",'C1') as CustomerID,
    nvl(T1."Key",T2."Key") as Key,
    T1."Value" as Value,
    nvl(T2."CustomerID",'C2') as CustomerID,
    nvl(T2."Key",T1."Key") as Key,
    nvl(T1."Key",null) as Value
 from (
     select  * from T where "CustomerID" = 'C1'
 ) T1
 full outer join (
     select  * from T where "CustomerID" = 'C2'
 ) T2
 on T1."Key" = T2."Key"
CUSTOMERID | KEY        | VALUE         | CUSTOMERID | KEY        | VALUE     
:--------- | :--------- | :------------ | :--------- | :--------- | :---------
C1         | AskPhoneNo | TRUE          | C2         | AskPhoneNo | AskPhoneNo
C1         | Report     | TRUE          | C2         | Report     | Report    
C1         | AskAddress | null          | C2         | AskAddress | null      
C1         | Website    | C1Website.com | C2         | Website    | Website   

db<>fiddle here

Upvotes: 0

T.S.
T.S.

Reputation: 19386

Are you going to compare data only between 2 customers?

Select 
    cust1, key1, val1,
    cust2, key2, val2      
from
    (select CustomerID cust1, key key1, value val1
     from myTable
     where CustomerID = 1) c1 inner join 
    (select CustomerID cust2, key key2, value val2
     from myTable
     where CustomerID = 2) c2 on 
        c1.key1 = c2.key2;

I hope, this is self-explanatory. But this particular SQL will work only if you have cust1 and cust2 values. If some of them missing, we need use left and right joins, or a FULL JOIN

Upvotes: 0

user5683823
user5683823

Reputation:

There are two problems with your required output. First, there's no point in the constant columns (with values C1 and C2 respectively), and there's no reason to repeat the key names. Second, your output seems to show ALL the rows, not just the "differences". If you need to show ALL the rows (whether the values are the same or different), just remove the where clause below.

with
  test_data(customer_id, key, value) as (
    select 'C1', 'AskPhoneNo', 'TRUE'          from dual union all
    select 'C1', 'Website'   , 'C1Website.com' from dual union all
    select 'C1', 'Report'    , 'TRUE'          from dual union all
    select 'C2', 'AskPhoneNo', 'TRUE'          from dual union all
    select 'C2', 'Report'    , 'FALSE'         from dual union all
    select 'C2', 'AskAddress', 'TRUE'          from dual union all
    select 'C3', 'AskAddress', 'FALSE'         from dual union all
    select 'C3', 'Report'    , 'TRUE'          from dual union all
    select 'C3', 'Website'   , 'C3web.edu'     from dual
  )
-- End of simulated inputs (for testing only, not part of the solution!)
select key, c1_value, c2_value
from   test_data
pivot  (max(value) for customer_id in ('C1' as c1_value, 'C2' as c2_value))
where  decode(c1_value, c2_value, 0, 1) = 1  -- If needed
order  by key                                -- If needed
;

KEY        C1_VALUE      C2_VALUE     
---------- ------------- -------------
AskAddress               TRUE         
Report     TRUE          FALSE        
Website    C1Website.com              

Upvotes: 1

Related Questions