检索循环图数据,无需无限循环和重复

Retrieve cyclic graph data without infinite loop and repeated

提问人:lady 提问时间:11/12/2023 最后编辑:lady 更新时间:11/14/2023 访问量:81

问:

我需要查询这些记录以获取唯一的相关项目:

insert into items(child, parent) 
values (1, 2), (2, 3), (3, 5), (3, 4),
       (4, 5), (6, 7), (1, 8), (8, 1)

我需要传递输入,例如 1 并获取相关项目的结果

 2 3 4 5 8

我尝试过 SQL / CTE,但我失败了。

因此,我需要任何带有 VB.NET 或SQL帮助的解决方案,并考虑大数据。

============ 添加查询

 WITH Alter_RC AS ( 
      SELECT sa1.child,
          sa1.parent,
          CAST(concat(LOWER( sa1.child), ',', LOWER( sa1.parent)) as  nvarchar(MAX)) as relpath
          FROM items sa1
          WHERE LOWER( sa1.child ) =   LOWER(  '1'  )
    UNION ALL
       SELECT  sa1.child,
           sa1.parent,
           CAST( concat(sa2.relpath, ',', sa1.parent) as nvarchar(MAX)) as relpath
           FROM Alter_RC as sa2 inner join items as sa1 on sa2.parent = sa1.child
           where LOWER( sa1.parent  ) NOT IN  (SELECT value FROM STRING_SPLIT(relpath, ','))
     )
     SELECT  parent FROM  Alter_RC  
     OPTION (MAXRECURSION 0);

输出

2 8 3 5 4 5
SQL vb.net 循环 公表表达式

评论

0赞 Dai 11/12/2023
“我尝试过SQL / CTE,但我失败了。”- 向我们展示您的 CTE 查询。
0赞 lady 11/12/2023
我尝试了许多其他查询,并添加了其中一个......我不需要任何带有选择不同的解决方案。因为当我有大数据时,性能会很差..
0赞 Dai 11/12/2023
你熟悉SARGability的概念吗?
0赞 lady 11/12/2023
不,但如果它能帮助我,没问题
1赞 Christoph 11/13/2023
我在这里发布了一个解决方案,该解决方案对于组中组解析等非常有效。如果不重写一点,它可能无法扩展,但可以提示您朝着正确的方向前进:stackoverflow.com/questions/66082516/......

答:

0赞 Saikat 11/13/2023 #1

下面是在 SQL Server 中使用递归 CTE 的解决方案。请试一试。我不确定它的效果如何。但它肯定会给你你正在寻找的答案。

with main_cte as
    (
    select distinct
        case when parent > child then child 
            else parent end as child , 
        case when parent < child then child 
            else parent end as parent
    from items
    ) ,            
cte as
    (
        select  child , parent from main_cte as a
        union all
        select  a.child , b.parent from cte as a inner join main_cte as b on a.parent = b.child
    ),
base_cte as
    (
        select parent as child , child as parent from main_cte as a
    ),
next_cte as
    (
        select child , parent from base_cte as a
        union all
        select b.child , a.parent from next_cte as a inner join base_cte as b on a.child = b.parent
        union all
        select b.child , a.child from next_cte as a inner join base_cte as b on a.parent = b.parent
    ) , 
final_cte as
(
    select child as person  , parent as relatives from
    (
        select child , parent from cte 
        union all
        select child , parent from next_cte 
        where child <> parent
    ) as a
    group by child , parent
)
select person , string_agg(cast(relatives as varchar(1)) , ',') as realtives from final_cte group by person;

            

评论

0赞 lady 11/13/2023
执行不会停止!,我在哪里可以添加:where child = LOWER( '1' ) ?
0赞 lady 11/13/2023
适用于此检查: CREATE TABLE ##test ( 子 nvarchar(50), parent nvarchar(50) ) 插入 ##test ( 子项, 父项) 值 (1, 2), (2, 3), (3, 5), (3, 4), (4, 5), (6, 7), (1, 8), (8, 1) ---- 对于特定项目
0赞 Saikat 11/13/2023
所以你需要特定输入的输出吗?其中 child = 1?这是可能的,但我不明白的是最后的记录。如果 1 的父级是 8,那么反过来怎么可能呢?- 请解释。因此,如果您删除最后一条记录,那么您可以获得所需的输出。如果我在任何地方错了,请告诉我。
0赞 lady 11/13/2023
这些记录中的主要问题是,由于多种方式的循环结果......特别是如果同一个父母在两个不同的兄弟姐妹中......实际上,真实数据更复杂
1赞 Saikat 11/14/2023
好的,明白了。这有效吗?因为我没有看到你有什么数据。我只是尝试在您提供的数据集上执行此操作。
0赞 lady 11/14/2023 #2

我解决了 VB.NET 的问题,因为我需要检查重复的项目,如下所示:

Dim relateditems As New List(Of String)

Private Sub RetreiveItems(item As String)
    Dim watch As Stopwatch = Stopwatch.StartNew()
    relateditems.Add(item)
    Dim Where = " LOWER( sa1.child ) = LOWER('" & item & "' ) "
    RecursivelyRetreiveItems(Where) 
    watch.Stop() 
    Console.WriteLine(relateditems.Count & " " & watch.Elapsed.TotalMilliseconds)
End Sub

Private Sub RecursivelyRetreiveItems(Where As String)
    Dim dt = selectSQLData("SELECT sa1.child as currentItem, sa1.parent as parentItem  FROM items sa1 WHERE " & Where & " and fitem_Different_yn = '0' ").Tables(0)

    For i = 0 To dt.Rows.Count - 1
        If relateditems.Contains(dt.Rows(i)("parentItem").ToString) = False Then
            relateditems.Add(dt.Rows(i)("parentItem"))
        End If
    Next

    If dt.Rows.Count > 0 Then
        Dim newWhere = "("
        For i = 0 To dt.Rows.Count - 1
            If newWhere <> "(" Then
                newWhere += " OR "
            End If
            newWhere += "LOWER(sa1.child) = LOWER('" & dt.Rows(i)("parentItem") & "' ) "
        Next
        newWhere += ") and (" & ("'" + String.Join(",", relateditems) + "'") & " not LIKE concat('%', sa1.parent, '%')     ) "

        RecursivelyRetreiveItems(newWhere)
    End If
End Sub