Отметить людей, которые имеют общие функции с Oracle SQL - PullRequest
0 голосов
/ 03 октября 2018

Рассмотрим следующую таблицу:

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] - график с идентификатором 1 (см. https://en.wikipedia.org/wiki/Connectivity_(graph_theory)).. Проблема эквивалентна этой проблеме , однако я хотел бы решить ее с помощью Oracle SQL.

1 Ответ

0 голосов
/ 03 октября 2018

Вот один из способов сделать это, используя иерархический («подключиться») запрос.Первым шагом является извлечение начальных отношений из базовых данных;иерархический запрос строится на результате этого первого шага.Я добавил еще одну строку к входам, чтобы проиллюстрировать сам узел, который является подключенным компонентом.

Вы пометили подключенные компоненты как A и B - конечно, это не будет работать, если у вас есть, скажем,30000 подключенных компонентов.В моем решении я использую минимальное имя узла в качестве маркера для каждого подключенного компонента.

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 как FLAGк базовым данным вы можете сделать это с помощью тривиального соединения.

...