Для этого требуется рекурсивный CTE. Вы можете назначить группу, создавая ребра между электронными письмами (или именами), а затем пересекая график:
with edges as (
select t1.email as email1, t2.email as email2
from t join
t t2
on t1.name = t2.name
),
cte as (
select email1, email2, least(email1, email2) as min_email
array_construct(email1, email2) as visited
from edges e
union all
select cte.email1, e.email2, least(cte.min_email, e.email2),
array_append(cte.visited, e.email2)
from cte join
edges e
on cte.email2 = e.email1
where not array_contains(cte.visited, e.email2)
)
select email1, min(min_email),
dense_rank() over (order by min_email) as grp
from cte
group by email1;
Настройка этого присваивает grp
исходным данным:
with edges as (
select t1.email as email1, t2.email as email2
from t join
t t2
on t1.name = t2.name
),
cte as (
select email1, email2, least(email1, email2) as min_email
array_construct(email1, email2) as visited
from edges e
union all
select cte.email1, e.email2, least(cte.min_email, e.email2),
array_append(cte.visited, e.email2)
from cte join
edges e
on cte.email2 = e.email1
where not array_contains(cte.visited, e.email2)
)
select t.*, grp
from t join
(select email1, min(min_email) as min_email,
dense_rank() over (order by min_email) as grp
from cte
group by email1
) e
on t.email = e.email;