循环图数据去重无无限循环查询求助(SQL/VB.NET,支持大数据)
SQL 解决方案(无重复、防循环)
核心思路是在递归CTE中维护已访问节点集合,每次递归前检查目标节点是否已被访问,避免重复遍历和无限循环,同时确保结果唯一。
改进后的CTE查询
WITH RecursiveRelations AS ( -- 初始节点:从输入值1出发的直接父节点 SELECT child, parent, -- 用逗号包裹节点值存储已访问集合,便于快速判断 CAST(',' + LTRIM(STR(child)) + ',' + LTRIM(STR(parent)) + ',' AS NVARCHAR(MAX)) AS VisitedNodes FROM items WHERE child = 1 UNION ALL -- 递归遍历:仅处理未访问过的节点 SELECT i.child, i.parent, -- 更新已访问节点集合 CAST(rr.VisitedNodes + LTRIM(STR(i.parent)) + ',' AS NVARCHAR(MAX)) AS VisitedNodes FROM RecursiveRelations rr INNER JOIN items i ON rr.parent = i.child -- 关键过滤:确保当前父节点未被访问过,避免重复和循环 WHERE CHARINDEX(',' + LTRIM(STR(i.parent)) + ',', rr.VisitedNodes) = 0 ) -- 去重并返回有序的关联节点 SELECT DISTINCT parent AS RelatedItem FROM RecursiveRelations ORDER BY RelatedItem;
关键说明
- VisitedNodes字段:用逗号包裹节点值(如
,1,2,),通过CHARINDEX快速判断节点是否已被访问,比STRING_SPLIT效率更高,适合大数据场景。 - 递归终止逻辑:通过
CHARINDEX检查父节点是否在已访问集合中,彻底避免无限循环(比如1和8的互指关系,第一次遍历到8后,后续不会再从8回到1)。 - DISTINCT去重:确保最终结果没有重复项(比如原查询中重复出现的5会被合并)。
执行上述查询,输入值1时会得到预期结果:2 3 4 5 8。
VB.NET 解决方案(支持大数据、防重复循环)
如果数据量极大,纯SQL递归可能存在性能瓶颈,可采用VB.NET结合**哈希集合(HashSet)**实现高效遍历,哈希集合的查找时间复杂度为O(1),天然适配去重和防循环需求。
实现代码
Imports System.Data.SqlClient Imports System.Collections.Generic Imports System.Linq Public Function GetUniqueRelatedItems(startChild As Integer) As List(Of Integer) Dim connectionString As String = "你的数据库连接字符串" Dim relatedItems As New HashSet(Of Integer)() Dim traverseQueue As New Queue(Of Integer)() ' 初始化:获取起始节点的直接父节点 Using conn As New SqlConnection(connectionString) conn.Open() Dim initialQuery As String = "SELECT parent FROM items WHERE child = @StartChild" Using cmd As New SqlCommand(initialQuery, conn) cmd.Parameters.AddWithValue("@StartChild", startChild) Using reader As SqlDataReader = cmd.ExecuteReader() While reader.Read() Dim parent As Integer = reader.GetInt32(0) ' 哈希集合自动去重,添加成功则加入遍历队列 If relatedItems.Add(parent) Then traverseQueue.Enqueue(parent) End If End While End Using End Using ' 广度优先遍历(BFS),避免深度优先的栈溢出,适合大数据场景 While traverseQueue.Count > 0 Dim currentNode As Integer = traverseQueue.Dequeue() Dim childQuery As String = "SELECT parent FROM items WHERE child = @CurrentNode" Using cmd As New SqlCommand(childQuery, conn) cmd.Parameters.AddWithValue("@CurrentNode", currentNode) Using reader As SqlDataReader = cmd.ExecuteReader() While reader.Read() Dim parent As Integer = reader.GetInt32(0) If relatedItems.Add(parent) Then traverseQueue.Enqueue(parent) End If End While End Using End Using End Using End Using ' 返回有序结果 Return relatedItems.OrderBy(Function(x) x).ToList() End Function
关键说明
- HashSet的作用:自动处理重复项,
Add方法返回布尔值,仅当元素未存在时才添加成功,天然避免重复和循环。 - 广度优先遍历(BFS):用队列实现,比深度优先更适合大数据场景,避免递归栈溢出问题。
- 性能优化:建议给
items表的child字段建立索引,减少数据库查询的耗时。
调用示例:
Dim result As List(Of Integer) = GetUniqueRelatedItems(1) Console.WriteLine(String.Join(" ", result)) ' 输出:2 3 4 5 8
内容的提问来源于stack exchange,提问作者lady
相关产品推荐
相关产品推荐

