Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/75.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 找出图是否有一个圈_Sql_Infinite Loop_Recursive Query - Fatal编程技术网

Sql 找出图是否有一个圈

Sql 找出图是否有一个圈,sql,infinite-loop,recursive-query,Sql,Infinite Loop,Recursive Query,我想知道是否可以使用SQL在分层数据或链数据中查找周期 例如,我有以下模式: 在图形中具有相同ID的表记录属于一个图形 我需要一个查询,它将返回至少有一个循环的所有图的ID 例如,上面的查询应该返回1,这是第一个图形的id 首先,我假设这是一个有向图。如果一个无向图包含一条边,它就有一个平凡的圈 递归CTE唯一棘手的部分是在达到一个周期时停止——这样就不会得到无限递归 试试这个: with cte as ( select e.object_a, e.object_b, iscycl

我想知道是否可以使用SQL在分层数据或链数据中查找周期

例如,我有以下模式:

图形中
具有相同ID的表记录属于一个图形

我需要一个查询,它将返回至少有一个循环的所有图的ID


例如,上面的查询应该返回
1
,这是第一个图形的id

首先,我假设这是一个有向图。如果一个无向图包含一条边,它就有一个平凡的圈

递归CTE唯一棘手的部分是在达到一个周期时停止——这样就不会得到无限递归

试试这个:

with cte as (
      select e.object_a, e.object_b, iscycle = 0
      from edges e
      union all
      select cte.object_a, e.object_b,
             (case when cte.object_a = e.object_b then 1 else 0 end) as iscycle
      from cte join
           edges e
           on cte.object_b = e.object_a
      where iscycle = 0
     )
select max(iscycle)
from cte;

我根据@gordon linoff的答案编写了SQL查询。在某些情况下,我有无限循环,所以我添加了带有
node\u path
的列,然后检查当前连接是否出现在该列中

这是一个脚本:

create table edges (
   node_a varchar(20),
   node_b varchar(20)
);

INSERT INTO edges VALUES ('A', 'B'), ('A', 'C'), ('A', 'D'), ('B', 'D'), ('D', 'K'), ('K', 'A')
GO

with cte as (
    SELECT 
          e.node_a
        , e.node_b
        , 0 as depth 
        , iscycle = 0
        , CAST(e.node_a +' -> '+ e.node_b AS varchar(MAX)) as nodes_path
    FROM edges e

    UNION ALL

    SELECT 
          cte.node_a
        , e.node_b
        , depth + 1
        , (case when cte.node_a = e.node_b then 1 else 0 end) as iscycle
        , CAST(cte.nodes_path+' -> '+ e.node_b AS varchar(MAX)) as nodes_path
    FROM cte 
        JOIN edges e ON cte.node_b = e.node_a AND cte.nodes_path NOT LIKE '%' + CAST(cte.node_a+' -> '+ e.node_b AS varchar(500)) + '%' 
    where iscycle = 0 
    )
SELECT * -- max(iscycle)
FROM cte
option (maxrecursion 300) --just for safety :)

我不知道在有数百万条记录的地方它是否有效,因此如果你能看到我可以更优化地编写此查询,请分享你的意见。

你能澄清什么是
循环吗?
1
是正确答案吗,因为它的边缘记录从1-2-3-4-1开始?如果它变为1-2-1,它会是一个循环吗?或者它必须是对象表中的所有值吗?1-2-1也是一个循环。这个循环需要在图表表中进行检查,对吗?@Rajesh。我认为数据结构让我困惑。我明白了这个想法,尽管答案并不完全基于模式。thanks@bulat . . . 我真的不懂数据结构。边连接节点(似乎称为对象)。我不知道在你的词汇表中,
图形是什么,但我可以想象,
表中有一个
图形
列。你可以把它想象成公交线路,对象是公交车站。如果你认为grap_id是一个公共汽车号码,我想找到所有有自行车路线的公共汽车号码。
create table edges (
   node_a varchar(20),
   node_b varchar(20)
);

INSERT INTO edges VALUES ('A', 'B'), ('A', 'C'), ('A', 'D'), ('B', 'D'), ('D', 'K'), ('K', 'A')
GO

with cte as (
    SELECT 
          e.node_a
        , e.node_b
        , 0 as depth 
        , iscycle = 0
        , CAST(e.node_a +' -> '+ e.node_b AS varchar(MAX)) as nodes_path
    FROM edges e

    UNION ALL

    SELECT 
          cte.node_a
        , e.node_b
        , depth + 1
        , (case when cte.node_a = e.node_b then 1 else 0 end) as iscycle
        , CAST(cte.nodes_path+' -> '+ e.node_b AS varchar(MAX)) as nodes_path
    FROM cte 
        JOIN edges e ON cte.node_b = e.node_a AND cte.nodes_path NOT LIKE '%' + CAST(cte.node_a+' -> '+ e.node_b AS varchar(500)) + '%' 
    where iscycle = 0 
    )
SELECT * -- max(iscycle)
FROM cte
option (maxrecursion 300) --just for safety :)