I have a table that contains small groups of related nodes. I would like to be able to identify all the nodes that are related.
-- Example of some small related nodes.
-- (14) (5) (8) (10) (3)
-- / \ \ \ /
-- (11)-(2) (12)-(9) (7)
-- \ / / \
-- (4) (6) (1) (13)
DECLARE @Graph TABLE (
A SmallInt NOT NULL,
B SmallInt NOT NULL
)
INSERT INTO @Graph (A, B)
VALUES
(11, 2), ( 2, 14), ( 2, 4), ( 5, 12),
( 6, 12), ( 12, 9), ( 8, 9), (10, 7),
( 1, 7), ( 7, 13), ( 7, 3);
WITH Src AS (
SELECT A, B FROM @Graph
)
, Recurse (A, B) AS (
SELECT A, B FROM Src
UNION ALL
SELECT S.A, R.B FROM Src S INNER JOIN Recurse R ON S.B = R.A
)
, List AS (
SELECT A, B FROM Recurse
UNION SELECT A, A FROM Src
UNION SELECT B, B FROM Src
)
SELECT A, MAX(B) B FROM List GROUP BY A ORDER BY 1, 2;
I decided to use the MAX node number to relate the nodes together, but some other method would be acceptable.
EzLo has to get credit for leading me to another post (How to find all connected subgraphs of an undirected graph) that allowed me to compose the correct answer.
DECLARE @Graph TABLE (
A SmallInt NOT NULL,
B SmallInt NOT NULL
)
INSERT INTO @Graph (A, B)
VALUES
(11, 2), ( 2, 14), ( 2, 4), ( 5, 12),
( 6, 12), ( 12, 9), ( 8, 9), (10, 7),
( 1, 7), ( 7, 13), ( 7, 3);
WITH CTE_Idents AS (
SELECT A AS Ident FROM @Graph
UNION SELECT B AS Ident FROM @Graph
)
, CTE_Pairs AS (
SELECT A AS Ident1, B AS Ident2 FROM @Graph WHERE A <> B
UNION SELECT B AS Ident1, A AS Ident2 FROM @Graph WHERE A <> B
)
, CTE_Recursive AS (
SELECT
CTE_Idents.Ident AS AnchorIdent,
Ident1,
Ident2,
CAST(',' + CAST(Ident1 AS VARCHAR(2)) + ',' + CAST(Ident2 AS VARCHAR(2)) + ',' AS varchar(8000)) AS IdentPath
FROM
CTE_Pairs
INNER JOIN
CTE_Idents
ON CTE_Idents.Ident = CTE_Pairs.Ident1
UNION ALL
SELECT
CTE_Recursive.AnchorIdent,
CTE_Pairs.Ident1,
CTE_Pairs.Ident2,
CAST(CTE_Recursive.IdentPath + CAST(CTE_Pairs.Ident2 AS VARCHAR(2)) + ',' AS varchar(8000)) AS IdentPath
FROM
CTE_Pairs
INNER JOIN
CTE_Recursive
ON CTE_Recursive.Ident2 = CTE_Pairs.Ident1
WHERE
CTE_Recursive.IdentPath NOT LIKE CAST('%,' + CAST(CTE_Pairs.Ident2 AS VARCHAR(2)) + ',%' AS varchar(8000))
)
, CTE_RecursionResult AS (
SELECT AnchorIdent, Ident1, Ident2 FROM CTE_Recursive
)
, CTE_CleanResult AS (
SELECT AnchorIdent, Ident1 AS Ident FROM CTE_RecursionResult
UNION SELECT AnchorIdent, Ident2 AS Ident FROM CTE_RecursionResult
)
SELECT AnchorIdent, MAX(Ident) AS Ident FROM CTE_CleanResult GROUP BY AnchorIdent ORDER BY AnchorIdent
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With