i have a table which has 2 columns like this, picture is input and output:
Explain input: 2 column is 2 person who relation ship together. Exam: A relation with B, C,D,H Output: i want to merge 2 column , with Column group ID auto and column RelationShip
- ID group auto: i tried query: row_number() OVER (ORDER BY [columnA]) n
- RelationShip: is group all person relatioship together and group them to 1 ID group. Exam person A,B,C,D,H realation ship together and group id auto is 1
I have a demo in https://dbfiddle.uk/?rdbms=sqlserver_2019&fiddle=f81ff386b07589654ad133a8e4b30472
In my query, first i turn the data into a single column, second i count letter, next step i don’t know query.
I tried recursive CTE but error (perhaps I don’t understand clearly about recursive)
I want to solve this problem in sql query.
Advertisement
Answer
You can use a recursive CTE to assign each “column” value a number. This starts by created edges in both directions and then following them:
with pairs as ( select columnA, columnB from myTable union -- on purpose to remove duplicates select columnB, columnA from myTable ), cte as ( select distinct columnA, columnA as columnB, convert(varchar(max), ',' + columnA + ',') as visited, 1 as lev from pairs union all select cte.columnA, p.columnB, concat(visited, p.columnA, ','), lev + 1 from cte join pairs p on cte.columnB = p.columnA where cte.visited not like concat('%,', p.columnB, ',%') and lev < 5 ) select cte.columnA, min(cte.columnB), dense_rank() over (order by min(cte.columnB)) from cte group by cte.columnA;
You can then join this in to assign a group id:
with pairs as ( select columnA, columnB from myTable union -- on purpose to remove duplicates select columnB, columnA from myTable ), cte as ( select distinct columnA, columnA as columnB, convert(varchar(max), ',' + columnA + ',') as visited, 1 as lev from pairs union all select cte.columnA, p.columnB, concat(visited, p.columnA, ','), lev + 1 from cte join pairs p on cte.columnB = p.columnA where cte.visited not like concat('%,', p.columnB, ',%') and lev < 5 ), groups as ( select cte.columnA, min(cte.columnB) as min_columnB, dense_rank() over (order by min(cte.columnB)) as group_id from cte group by cte.columnA ) select t.*, g.group_id from mytable t join groups g on g.columnA = t.columnA;
Here is a db<>fiddle.