简体   繁体   中英

Oracle, find differences in records between two "sets"

Some scripts:

create table set_1
( id number(12));

create table set_2
( id number(12));

create table map_set
( id_set_1 number(12),
  id_set_2 number(12)
);
  
  
  insert into set_1 values(1);
  insert into set_1 values(2);
  insert into set_1 values(3);
  insert into set_1 values(4);
  
  insert into map_set values(1,5);
  insert into map_set values(2,6);
  insert into map_set values(3,7);
  insert into map_set values(4,8);
  
  insert into set_2 values(5);
  insert into set_2 values(6);
  insert into set_2 values(7);
  insert into set_2 values(8);

create table attrib_1(
id           number(12),
set_id       number(12),
attrib_id    number(2),
val          number(10,2));

create table attrib_2
(
id number(12),
set_id number(12),
attrib_id number(2),
val       number(10,2)
);

insert into attrib_1 values(1,1,1,10.2);
insert into attrib_1 values(2,1,2,2.5);
insert into attrib_1 values(3,1,3,5.23);

SELECT * FROM attrib_1;

insert into attrib_2 values(1,5,2,4.54);
insert into attrib_2 values(2,5,3,89.5);

There is a - let's call them sets. There is also a table which mapping this sets, so in this case fe set from set_1 table with id = 1 is a copy of set_2 with id =2. Sets can have attributes, one or more. Then we make some changes in this attrib sets.

What I want is to detect differences between this attributes between "same" sets. I've wrote this:

   SELECT  *
    FROM    (
              SELECT a1.id       ,
                     a1.attrib_id,
                     a1.val      ,
                     s1.id  AS set_id,
                     mp.id_set_2
              
              FROM   set_1   s1,
                     map_Set mp,
                     attrib_1 a1
              WHERE  mp.id_set_1 = s1.id
              AND    s1.id = 1
              and    a1.set_id = S1.id
            ) s1
    full    join
            (
              SELECT a2.id       ,
                     a2.attrib_id,
                     a2.val      ,
                     s2.id  AS set_id
              FROM   set_2   s2,
                     attrib_2 a2
              WHERE  s2.id = 5
              and    a2.set_id = S2.id
            ) s2
    ON      s1.id_set_2 = s2.set_id
    AND     s1.attrib_id = s2.attrib_id

I want to create for.. loop plsql code where it gets all records and:

  • if attrib_id's are the same and val is different - update record
  • if there is attrib in set_2 but missing in set_1 - delete
  • if there is attrib in set_1 but missing in set_2 - add and here's the problem:

在此处输入图像描述

I need an id of set to do INSERT, but there is no id "empty attrib" records.

I want output to look like this:

在此处输入图像描述

  • to have ALL data about sets, and left join attributes.

I tried left joins, this is closest I've got to my goal but now I'm stuck.

Any ideas? Thanks!

Edit: i prefer to do this in one SQL. Triggers on tables forbides operatioms on few id's in one insert.

You want to perform three operations. They can be done with three separate queries:

1. If attrib_id's are the same and val is diffrent - update record

update (
  select x.*, u.bval
  from attrib_1 x
  join (
    select
      m.*, a.attrib_id as aid, a.val as aval, b.val as bval
    from map_set m
    join attrib_1 a on a.set_id = m.id_set_1
    full join attrib_2 b on b.set_id = m.id_set_2 and b.attrib_id = a.attrib_id
  ) u on u.aid = x.attrib_id and u.aval <> u.bval
)
set val = bval

2. If there is attrib in set_2 but missing in set_1 - delete

delete from attrib_2
where (set_id, attrib_id) in (
  select b.set_id, b.attrib_id
  from map_set m
  join attrib_1 a on a.set_id = m.id_set_1
  right join attrib_2 b on b.set_id = m.id_set_2 and b.attrib_id = a.attrib_id
  where a.set_id is null
);

3. If there is attrib in set_1 but missing in set_2 - add

insert into attrib_2 (id, set_id, attrib_id, val)
select
  100, -- probably use an identity or sequence
  m.id_set_2, a.attrib_id, a.val
from map_set m
join attrib_1 a on a.set_id = m.id_set_1
left join attrib_2 b on b.set_id = m.id_set_2 and b.attrib_id = a.attrib_id
where b.set_id is null

Final Result:

 ID_SET_1  ID_SET_2  AID  AVAL  BVAL 
 --------- --------- ---- ----- ---- 
 1         5         1    10.2  10.2 
 1         5         2    4.54  4.54 
 1         5         3    89.5  89.5 

See running example at db<>fiddle . I added one extra row to your example to test case #3 (add).

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