我有两个相似的表层次结构:
Owner -> OwnerGroup -> Parent
和
Owner2 -> OwnerGroup2
我想根据一组值确定Owner2中是否存在所有者的完全匹配。每个Owner表中有大约一百万行。一些OwnerGroup最多包含100个所有者。
所以基本上如果有一个OwnerGroup而不是包含Owners“Smith”,“John”和“Smith,”Jane“,我想知道所有者Group2的id是完全匹配的。
第一次尝试是为每个所有者生成一个连接(需要在应用程序中生成动态sql:
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');
这适用于少数所有者,但是当我们必须在组场景中处理100个所有者时,因为此查询计划意味着有100个嵌套循环,并且运行将花费将近一分钟。
我的另一个选择是在intersect
运算符周围使用某些东西。 E.g。
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;
我不确定如何在这种情况下剔除owner2.id - 它仍然在4-5秒范围内运行。
我觉得我错过了一些明显的东西 - 所以请随意提供一些更好的解决方案!
答案 0 :(得分:0)
您使用intersect
走在正确的轨道上,您只需要更进一步。您需要将其结果加回owner_groups2
表以查找ID。
您可以使用listagg
功能将组转换为逗号分隔的名称列表(注意 - 需要11g)。然后,您可以使用这些名称列表的交集来查找匹配项,并将其连接回owner_groups2
中的列表。
我在下面创建了一个简化示例,其中“Dave,Jill”是两个表中都存在的组。
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
);
请注意,这仍然需要owner_groups2
的完整扫描;我想不出一种可以避免这种情况的方法。所以你的查询可能会保持缓慢。