将查询结果拆分为唯一集

时间:2017-10-02 11:24:07

标签: c# graph tsql

我有一个返回两列的查询,它代表两个实体(直接或间接)之间的关系,例如右边图表中显示的关系将由右边表格中的数据表示: / p>

| From | To |          1    3    4
|------|----|          o----o----o
| 1    | 3  |              / \
| 1    | 4  |             /   \
| 1    | 5  |          2 o     o 5
| 2    | 3  |                     
| 2    | 4  |
| 2    | 5  |
| 3    | 4  |          6    7
| 3    | 5  |          o----o
| 6    | 7  |

我想要做的是将这些数据分组为多个集合,等于关系描述的不同图表的数量(在上例中为2集)。

此分组可以作为数据库查询(T-SQL)的一部分或数据在内存(C#)中发生。

1 个答案:

答案 0 :(得分:1)

它可能不漂亮,但这会正确地对顶点进行分组,并且只需要边缘作为起点。请注意,边的顶点顺序无关紧要。

-- Sample data.
declare @Edges as Table ( Vertex1 Int, Vertex2 Int );
insert into @Edges ( Vertex1, Vertex2 ) values
  ( 1, 3 ), ( 3, 4 ), ( 3, 2 ), ( 3, 5 ),
  ( 6, 7 );
select * from @Edges;

-- Create a working table that assigns each vertex to a unique "set".
declare @Sets as Table ( SetId Int, Vertex Int );
insert into @Sets ( SetId, Vertex )
  select Row_Number() over ( order by Vertex ), Vertex from (
    select distinct Vertex1 as Vertex from @Edges
    union
    select distinct Vertex2 from @Edges ) as PH;
select * from @Sets;

-- Update the working table to group vertexes into sets:
--   For each vertex update the   SetId  to the minimum   SetId  of all of the vertexes one edge away.
--   Repeat until nothing changes.
declare @UpdatedRows as Int = 42;
while @UpdatedRows > 0
  begin
  update NS
    set SetId = MinSetId
    from (
      select S.SetId, S.Vertex,
        ( select Min( SetId ) from @Sets where Vertex in (
          select S.Vertex union
          select Vertex1 from @Edges where Vertex2 = S.Vertex union
          select Vertex2 from @Edges where Vertex1 = S.Vertex )
          ) as MinSetId
        from @Sets as S ) as NS
    where SetId != MinSetId;
  set @UpdatedRows = @@RowCount;
  select * from @Sets;  -- Show the work as it progresses.
  end

  -- The   SetId   values can be collapsed using   Dense_Rank .
  select Dense_Rank() over ( order by SetId ) as SetId, Vertex
    from @Sets;