Запрос на группирование полностью рекурсивных отношений в соединительной таблице многие-ко-многим - PullRequest
0 голосов
/ 25 сентября 2018

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

Я называю это полностью рекурсивной группировкой в ​​отношениях «многие ко многим».Я попытался написать соединения и ctes, чтобы сделать это, но без полной рекурсии я получаю только один уровень глубины, и я не очень рад пытаться писать вложенные динамические курсоры.

Предположим, что выражения могут быть получены изэта таблица «соединения», чтобы найти отдельных студентов / классов, поэтому вопрос может быть обобщен с использованием только одного набора.

SELECT * FROM student_class

+-------------+----------+--------------+
| student_id  | class_id | group_number |
+-------------+----------+--------------+
| 1           | A        | null         |
| 1           | C        | null         |
| 2           | A        | null         |
| 2           | B        | null         |
| 2           | C        | null         |
| 3           | E        | null         |
| 4           | B        | null         |
| 4           | F        | null         |
+-------------+----------+--------------+ 

Вопрос в том, как заполнить номер группы посредством рекурсивных отношений для каждого учащегося и для каждого класса.Пример: если student_id 1 имеет class_id A, то какие еще студенты имеют class_id A?Для тех других учеников, какие у них другие классы?Для каждого из тех других классов, какие другие студенты имеют эти классы?Затем продолжайте повторять результаты до тех пор, пока не будет найдено никаких зависимостей.

Так что в этом примере окончательное обновление будет содержать только две группы, читайте так, поскольку ни у одного из учеников нет class_id C, а student_id 3 не имеет других классов:

+-------------+----------+--------------+
| student_id  | class_id | group_number |
+-------------+----------+--------------+
| 1           | A        | 1            |
| 1           | C        | 1            |
| 2           | A        | 1            |
| 2           | B        | 1            |
| 2           | C        | 1            |
| 3           | E        | 2            |
| 4           | B        | 1            |
| 4           | F        | 1            |
+-------------+----------+--------------+ 

1 Ответ

0 голосов
/ 25 сентября 2018

Это действительно сложно.Это алгоритм обхода графа (что не так сложно).Но вы должны определить график.Вы можете определить связь между двумя классами, используя самостоятельное соединение.Затем это можно использовать для рекурсивного CTE.

Итак, чтобы получить классы эквивалентностей (вроде как капризный здесь), вы можете сделать:

with cs as (
      select *
      from (values (1, 'A'), (1, 'C'), (2, 'A'), (2, 'B'), (2, 'C'), (3, 'E'), (4, 'B'), (4, 'F')) v(student, class)
     ),
     cc as (
      select distinct cs1.class as class1, cs2.class as class2
      from cs cs1 join
           cs cs2
           on cs1.student = cs2.student
     ),
     cte as (
      select cc.class1 as class, cc.class2 as grp, cast(',' + cc.class1 + ',' as varchar(max)) as grps
      from cc
      union all
      select cte.class, cc.class2, 
             cast(grps + cc.class2 + ',' as varchar(max)) as grps
      from cte join
           cc
           on cc.class1 = cte.grp and cte.grps not like '%,' + cc.class1 + ',%'
    )
select cte.class, min(cte.grp)
from cte
group by cte.class;

Если вы хотите преобразовать их в числа:

select cte.class, min(cte.grp),
       dense_rank() over (order by min(cte_grp)) as group_number
from cte
group by cte.class;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...