简体   繁体   中英

Matching a set of child records between two similar table hierarchies

I have two similar table hierarchies:

Owner -> OwnerGroup -> Parent

and

Owner2 -> OwnerGroup2

I would like to determine if there is an exact match of Owners that exists in Owner2 based on a set of values. There are approximately a million rows in each Owner table. Some OwnerGroups contain up to 100 Owners.

So basically if there is an OwnerGroup than contains Owners "Smith", "John" and "Smith, "Jane", I want to know the id of the OwnerGroup2s that are exact matches.

The first attempt at this was to generate a join per Owner (which required dynamic sql being generated in the application:

select og.id
from owner_group2 og
-- dynamic bit starts here
join owner2 o1 on
(og.id = o1.og_id) AND
(o1.given_names = 'JOHN' and o1.surname='SMITH')
-- dynamic bit ends here
join owner2 o2 on
(og.id = o2.og_id) AND
(o2.given_names = 'JANE' and o2.surname='SMITH');

This works fine until for small numbers of owners, but when we have to deal with the 100 Owners in a group scenario as this query plan means there 100 nested loops and it takes almost a minute to run.

Another option I had was to use something around the intersect operator. Eg

select * from ( 
select o.surname, o.given_names
from owner1 o1
join owner_group1 og1 on o1.og_id = og1.id 
where 
og1.parent_id = 1936233
)
intersect
select o.surname, o.given_names
from owner2 o2 
join owner_group2 og2 on og2.id = o2.og_id;

I'm not sure how to suck out the owner2.id in this scenario either - and it was still running in the 4-5 second range.

I feel like I am missing something obvious - so please feel free to provide some better solutions!

You're on the right track with intersect , you just need to go a bit further. You need to join the results of it back to the owner_groups2 table to find the ids.

You can use the listagg function to convert the groups into comma-separated lists of the names (note - requires 11g). You can then take the intersection of these name lists to find the matches and join this back to the list in owner_groups2 .

I've created a simplified example below, in it "Dave, Jill" is the group that is present in both tables.

create table grps (id integer, name varchar2(100));
create table grps2 (id integer, name varchar2(100));

insert into grps values (1, 'Dave');
insert into grps values(1, 'Jill');

insert into grps values (2, 'Barry');
insert into grps values(2, 'Jane');

insert into grps2 values(3, 'Dave');
insert into grps2 values(3, 'Jill');

insert into grps2 values(4, 'Barry');

with grp1 as (
 SELECT id, listagg(name, ',') within group (order by name) n 
 FROM grps
 group by id
), grp2 as (
 SELECT id, listagg(name, ',') within group (order by name) n 
 FROM grps2
 group by id
)
SELECT * FROM grp2 
where  n in (
  -- find the duplicates
  select n from grp1 
  intersect
  select n from grp2
);

Note this will still require a full scan of owner_groups2 ; I can't think of a way you can avoid this. So your query is likely to remain slow.

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