【问题标题】:sql detect cycle in directed graphsql检测有向图中的循环
【发布时间】:2019-07-02 18:57:25
【问题描述】:

我们有一个由边表表示的有向图。我们如何在纯 SQL 中检测循环?

CREATE TABLE edges(id integer primary key identity, from_node int, to_node int);
CREATE NONCLUSTERED INDEX index_edges_of2 ON edges(from_node);

INSERT INTO edges(from_node,to_node) VALUES(1,2),(2,3),(3,1);

【问题讨论】:

标签: sql sql-server


【解决方案1】:

对此的解决方案是递归 CTE。但是,要使其正常工作,您需要保留已访问节点的列表。 SQL Server 对此没有优雅的解决方案(例如数组),因此您需要使用字符串操作。

以下将列出图中的循环:

with cte as (
      select from_node, to_node, 
             convert(varchar(max), concat(',', from_node, ',', to_node, ',')) as nodes, 1 as lev, 
             (case when from_node = to_node then 1 else 0 end) as has_cycle
      from edges e
      union all
      select cte.from_node, e.to_node,
             convert(varchar(max), concat(cte.nodes, e.to_node, ',')), lev + 1,
             (case when cte.nodes like concat('%,', e.to_node, ',%') then 1 else 0 end) as has_cycle
      from cte join
           edges e
           on e.from_node = cte.to_node
      where cte.has_cycle = 0 
     )
select *
from cte
where has_cycle = 1;

Here 是数据库小提琴。

【讨论】:

  • 有趣的是,这列出了 [2,3,1,2]、[3,1,2,3] 和 [1,2,3,1]。我想知道这些是否应该算作同一个循环?
【解决方案2】:
WITH cte AS (
    SELECT CAST('.1.' AS varchar(1000)) AS gpath, 1 AS current_node, 0 AS Cycle

    UNION ALL

    SELECT CAST(CONCAT(gpath, '.', e.to_node, '.') AS varchar(1000)) AS gpath, e.to_node AS current_node, 0 AS cycle
    FROM cte
    JOIN edges AS e ON e.from_node = cte.current_node
    WHERE CHARINDEX(CONCAT('.',e.to_node,'.'),cte.gpath)=0 AND cte.Cycle=0

    UNION ALL

    SELECT CAST(CONCAT(gpath, '.', e.to_node, '.') AS varchar(1000)) AS gpath, e.to_node AS current_node, 1 AS cycle
    FROM cte
    JOIN edges AS e ON e.from_node = cte.current_node
    WHERE CHARINDEX(CONCAT('.',e.to_node,'.'),cte.gpath)>0 AND cte.Cycle=0
)
SELECT * FROM cte;

gpath current_node 周期

.1。 1 0

.1..2。 2 0

.1..2..3。 3 0

.1..2..3..1。 1 1

【讨论】:

    猜你喜欢
    • 2017-01-19
    • 1970-01-01
    • 1970-01-01
    • 2016-03-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-02
    • 1970-01-01
    相关资源
    最近更新 更多