我想知道是否可以使用SQL在Hierarchical或Chain数据中查找循环。
E.g。我有以下架构: http://sqlfiddle.com/#!3/27269
create table node (
id INTEGER
);
create table edges (
id INTEGER,
node_a INTEGER,
node_b INTEGER
);
create table graph (
id INTEGER,
edge_id INTEGER);
INSERT INTO node VALUES (1) , (2), (3), (4);
INSERT INTO edges VALUES (1, 1, 2), (2, 2, 3) , (3, 3, 4) , (4, 4, 1);
-- first graph [id = 1] with cycle (1 -> 2 -> 3 -> 4 -> 1)
INSERT INTO graph VALUES (1, 1), (1, 2), (1, 3), (1, 4);
-- second graph [id =2] without cycle (1 -> 2 -> 3)
INSERT INTO graph VALUES (2, 1), (2, 2), (2, 3);
在graph
表格中,具有相同ID的记录属于一个图表。
我需要一个查询,它将返回至少有一个周期的所有图表的ID。
例如,上面的查询应该返回1
,这是第一个图的id;
答案 0 :(得分:2)
首先,我假设这是一个有向图。如果无向图包含单个边,则它具有一个简单的循环。
递归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;
答案 1 :(得分:1)
我根据@ gordon-linoff回答编写了SQL查询。在某些情况下,我有无限循环,所以我添加了node_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 :)
我不知道数百万条记录是否有效,所以如果你能看到我可以更优化地写这个查询,请与你的意见分享。