Пометить дубликаты на основе одного из двух столбцов - PullRequest
0 голосов
/ 10 марта 2020

Допустим, мой набор данных выглядит следующим образом:

email name
  a    f
  b    g
  a    g
  o    k

и мой желаемый результат будет:

email name  group 
  a    f      1
  b    g      1
  a    g      1
  o    k      2

Поскольку первые три строки - это один и тот же человек, так как они совместно используют адрес электронной почты или фамилия. Я изо всех сил пытаюсь понять, как написать такой запрос, чтобы получить столбец группы.

1 Ответ

1 голос
/ 10 марта 2020

Для этого требуется рекурсивный 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;
...