标记与Oracle SQL具有共同功能的个人

时间:2018-10-03 14:14:36

标签: sql oracle oracle12c

请考虑下表:

ID  Feature
1   1
1   2
1   3
2   3
2   4
2   6
3   5
3   10
3   12
4   12
4   18
5   10
5   30

我想根据重叠特征对个人进行分组。如果这些组中的两个再次具有重叠的特征,那么我将两者都视为一个组。应该重复此过程,直到组之间没有重叠的功能。在上表中,此过程的结果将是:

ID  Feature Flag
1   1       A
1   2       A
1   3       A
2   3       A
2   4       A
2   6       A
3   5       B
3   10      B
3   12      B
4   12      B
4   18      B
5   10      B
5   30      B

所以实际上我要解决的问题是在图中找到连接的组件。这里[1,2,3]是ID为1的图形(请参见https://en.wikipedia.org/wiki/Connectivity_(graph_theory))。该问题等效于this problem,但是我想用Oracle SQL解决。

1 个答案:

答案 0 :(得分:0)

这是使用分层查询(“ connect by”)的一种方法。第一步是从基础数据中提取初始关系。分层查询基于第一步的结果。我在输入中又增加了一行,以说明一个节点本身就是一个连接的组件。

您将已连接的组件标记为A和B-当然,如果您有30,000个已连接的组件,则无法使用。在我的解决方案中,我使用最小节点名称作为每个连接组件的标记。

with
  sample_data (id, feature) as (
    select 1,  1 from dual union all
    select 1,  2 from dual union all
    select 1,  3 from dual union all
    select 2,  3 from dual union all
    select 2,  4 from dual union all
    select 2,  6 from dual union all
    select 3,  5 from dual union all
    select 3, 10 from dual union all
    select 3, 12 from dual union all
    select 4, 12 from dual union all
    select 4, 18 from dual union all
    select 5, 10 from dual union all
    select 5, 30 from dual union all
    select 6, 40 from dual
  )
-- select * from sample_data; /*
, initial_rel(id_base, id_linked) as (
    select distinct s1.id, s2.id
      from sample_data s1 join sample_data s2
                          on s1.feature = s2.feature and s1.id <= s2.id
  )
-- select * from initial_rel; /*
select     id_linked as id, min(connect_by_root(id_base)) as id_group
from       initial_rel
start with id_base <= id_linked
connect by nocycle prior id_linked = id_base and id_base < id_linked
group by   id_linked
order by   id_group, id
;

输出:

     ID   ID_GROUP
------- ----------
      1          1
      2          1
      3          3
      4          3
      5          3
      6          6

然后,如果您需要将ID_GROUP作为标志添加到基本数据中,则可以通过简单连接来实现。