我有两个表:ITEMS和MATCHING_ITEMS,如下所示:
ITEMS:
|---------------------|------------------|
| ID | Name |
|---------------------|------------------|
| 1 | A |
| 2 | B |
| 3 | C |
| 4 | D |
| 5 | E |
| 6 | F |
| 7 | G |
|---------------------|------------------|
MATCHING_ITEMS:
|---------------------|------------------|
| ID_1 | ID_2 |
|---------------------|------------------|
| 1 | 2 |
| 1 | 3 |
| 2 | 3 |
| 4 | 5 |
| 4 | 6 |
| 5 | 6 |
|---------------------|------------------|
MATCHING_ITEMS表定义了彼此匹配的项目,因此属于同一组,即项目1,2和3彼此匹配并因此属于一个组,而对于项目4,5和6.项目7不具有属于任何组的匹配项。
我现在需要在ITEMS表上添加一个“组”列,其中每个组都包含一个唯一的整数,因此它将如下所示:
ITEMS:
|---------------------|------------------|------------------|
| ID | Name | Group |
|---------------------|------------------|------------------|
| 1 | A | 1 |
| 2 | B | 1 |
| 3 | C | 1 |
| 4 | D | 2 |
| 5 | E | 2 |
| 6 | F | 2 |
| 7 | G | NULL |
|---------------------|------------------|------------------|
到目前为止,我一直在使用存储过程来执行此操作,遍历MATCHING_ITEMS表中的每一行,并使用组值更新ITEMS表。问题是我最终需要对包含数百万条记录的表执行此操作,并且循环方法太慢了。
有没有一种方法可以在不使用循环的情况下实现这一目标?
答案 0 :(得分:0)
您可以先使用min
和max
,然后使用dense_rank
分配组号:
select id, name, dense_rank() over (order by mn, mx) grp
from (
select distinct id, name,
min(id_1) over (partition by name) mn,
max(id_2) over (partition by name) mx
from items left join matching_items on id in (id_1, id_2))
order by id
答案 1 :(得分:0)
如果匹配表中有所有匹配项对,则可以使用最小ID来分配组。为此:
select i.*,
(case when grp_id is not null
then dense_rank() over (order by grp_id)
end) as grouping
from items i left join
(select mi.id_1, least(mi.id1, min(mi.id2)) as grp_id
from matching_items mi
group by mi.id_1
) mi
on i.id = mi.id_1;
注意:仅当所有对在匹配项表中时,此方法才有效。否则,您将需要递归/分层查询以获取所有对。
答案 2 :(得分:0)
Matching_items表中的2,3和5,6对似乎是多余的,因为它们可以派生出来(如果我没看错你的问题的话)
这就是我的做法。我只是将您示例中的id_1作为组号重复使用:
create table
items (
ID number,
name varchar2 (2)
);
insert into items values (1, 'A');
insert into items values (2, 'B');
insert into items values (3, 'C');
insert into items values (4, 'D');
insert into items values (5, 'E');
insert into items values (6, 'F');
insert into items values (7, 'G');
create table
matching_items (
ID number,
ID_2 number
);
insert into matching_items values (1, 2);
insert into matching_items values (1, 3);
insert into matching_items values (2, 3);
insert into matching_items values (4, 5);
insert into matching_items values (4, 6);
insert into matching_items values (5, 6);
with new_grp as
(
select id, id_2, id as group_no
from matching_items
where id in (select id from items)
and id not in (select id_2 from matching_items)),
assign_grp as
(
select id, group_no
from new_grp
union
select id_2, group_no
from new_grp)
select items.id, name, group_no
from items left outer join assign_grp
on items.id = assign_grp.id;