简体   繁体   中英

Oracle 12c - SQL Compare multiple rows based on master and detail record

I am working on migration process of legacy to a new one.

My legacy table example

Legacy table contains both master and child information's. I need to compare master and detail records in the row level and check any difference available

在此处输入图像描述

Detail record ID contains (-)

Please check and let me know how can I compare master with all the detail records and retrieve only different rows

在此处输入图像描述

My expectation output to get difference values which is record ID 30 and 30-10

I need to migrate different values to another table which I need to find first. Please comment if you need for information.

I need to compare DESC, CODE, CODE DESC, INDICATOR

Thanks in advance

You can use the analytical function as follows:

Select * from
(Select t.*,
       count( distinct indicator)
           over (partition by coalesce(substr(id,1,instr(id,'-') - 1),id)) 
       as distinct_indicator
  From your_table t)
Where distinct_indicator > 0;

You can add other columns here too. Two analytical function per column amd use them in where condition as i have used in the query.

You can also use self-join

SELECT a.ID || ' and ' || b.ID AS DIFF_VAL
FROM YOUR_TABLE a
JOIN YOUR_TABLE b ON a.id = SUBSTR(b.id, 1, INSTR(b.id, '-', -1, 1) -1)
WHERE a.INDICATOR!= b.INDICATOR
OR a.CODE!=b.CODE
--AND/OR keep your other conditions
with data (ID,DESCR, CODE, CODE_DESC, INDICATOR) as (
  select '10',    'DESC 10', 10, 'CODE DESC', 'NO' from dual union all
  select '10-10', 'DESC 10', 10, 'CODE DESC', 'NO' from dual union all
  select '10-11', 'DESC 10', 10, 'CODE DESC', 'NO' from dual union all
  select '10-12', 'DESC 10', 10, 'CODE DESC', 'NO' from dual union all
  select '20',    'DESC 20', 20, 'CODE DESC', 'NO' from dual union all
  select '20-10', 'DESC 20', 20, 'CODE DESC', 'NO' from dual union all
  select '20-11', 'DESC 20', 20, 'CODE DESC', 'NO' from dual union all
  select '30',    'DESC 30', 30, 'CODE DESC', 'NO' from dual union all
  select '30-10', 'DESC 30', 30, 'CODE DESC', 'YES' from dual union all
  select '30-20', 'DESC 30', 30, 'CODE DESC', 'NO' from dual
)
, data_with_master_id as (
  select data.*, nvl(substr(id,1,instr(id,'-')-1), id) master_id
  from data
)
select ID, DESCR, CODE, CODE_DESC, INDICATOR from (
  select dwmi.*,
    greatest(
      count(distinct descr) over(partition by master_id),
      count(distinct CODE) over(partition by master_id),
      count(distinct CODE_DESC) over(partition by master_id),
      count(distinct INDICATOR) over(partition by master_id)
    ) cnt_distinct,
    decode(descr, first_value(descr) over(partition by master_id order by id), 0, 1) +
    decode(CODE, first_value(CODE) over(partition by master_id order by id), 0, 1) +
    decode(CODE_DESC, first_value(CODE_DESC) over(partition by master_id order by id), 0, 1) +
    decode(INDICATOR, first_value(INDICATOR) over(partition by master_id order by id), 0, 1)
    diffs
  from data_with_master_id dwmi
)
where id = master_id and cnt_distinct > 1
or id != master_id and diffs > 0;

ID    DESCR         CODE CODE_DESC IND
----- ------- ---------- --------- ---
30    DESC 30         30 CODE DESC NO 
30-10 DESC 30         30 CODE DESC YES

Basically, you seem to want rows with codes that have more than one indicator value.

You can use window functions. A simple method is min() and max() :

select t.*
from (select t.*,
             min(indicator) over (partition by code) as min_indicator,
             max(indicator) over (partition by code) as max_indicator
      from t
     ) t
where min_indicator <> max_indicator;

If the codes are sufficient:

select code
from t
group by code
having min(indicator) <> max(indicator);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM