Добавление уникального номера для каждой группы не сложно, но требует нескольких шагов.
Первым шагом будет выбор уникальных значений для групп - например, группа с (1, 2)
и(2, 1)
будет содержать только одну запись - (1, 2)
.
Следующий шаг - избавиться от записей, создающих несколько путей для одной и той же связи - в данном случае - (3, 4), (4, 5), (3, 5)
- означает, что 5
относится как к 3
, так и к 4
, но для работы рекурсивного cte нам нужен только один путь отношений - так что либо (3, 4), (4, 5)
, либо (3, 4), (3, 5)
, но не оба.
Следующим шагом является создание рекурсивного cte на основе этих уникальных значений, чтобы каждая группа могла получить свой уникальный номер.
После этого вы можете выбрать исходный cte, присоединенный к рекурсивному cte, и получить уникальныйномера групп:
;WITH CTE AS
( SELECT *
FROM (VALUES (1,2)
,(2,1)
,(3,4)
,(3,5)
,(4,3)
,(4,5)
,(5,3)
,(5,4)
,(6,NULL)
,(7,NULL)
,(8,9)
,(9,8)
) AS ValuesTable(ID,RelatedID)
)
, PreUniqueValues AS
(
SELECT MIN(ID) AS ID,
MAX(RelatedID) As RelatedID
FROM CTE AS B
GROUP BY (ID + ISNULL(RelatedID, 0)) + (ID * ISNULL(RelatedID, 0))
)
, UniqueValues AS
(
SELECT ID, MIN(RelatedID) As RelatedID
FROM PreUniqueValues
GROUP BY ID
)
, Recursive AS
(
SELECT ID, RelatedId, DENSE_RANK() OVER(ORDER BY ID) As GroupID
FROM UniqueValues AS T0
WHERE NOT EXISTS
(
SELECT 1
FROM UniqueValues AS T1
WHERE T1.ID = T0.RelatedID
)
UNION ALL
SELECT UV.ID, UV.RelatedID, GroupID
FROM UniqueValues As UV
JOIN Recursive As Re
ON UV.ID = Re.RelatedId
)
SELECT CTE.ID, CTE.RelatedID, GroupID
FROM CTE
JOIN Recursive
ON CTE.ID = Recursive.ID OR CTE.ID = ISNULL(Recursive.RelatedID, 0)
ORDER BY ID
Результаты:
ID RelatedID GroupID
1 2 1
2 1 1
4 3 2
4 5 2
5 3 2
5 4 2
6 NULL 3
7 NULL 4
8 9 5
9 8 5