我想检测层次结构中的潜在周期。我有三个表,每个表有一个父表和一个子列:
Table1包含一些节点(在列子列中)及其父节点(在父列中); Table2包含Table1的所有父项(在列子项中)及其父项(在列父项中),依此类推。
例如,如果A是B的孩子,而B是C的孩子而C是A的孩子,那么我就有一个周期。
是否可以使用sql命令检测周期?
答案 0 :(得分:2)
您现在构建表的方式,以下SQL应该可以工作:
SELECT * FROM Table1
INNER JOIN Table2 on Table1.child = Table2.parent
INNER JOIN Table3 on Table2.child = Table3.parent
WHERE Table1.parent = Table3.child;
答案 1 :(得分:1)
这是一个适用于任意深度的解决方案。
将您的所有关系存储在一个表中:
Table t
Parent | Child
------ | -----
B | A
C | B
A | C
E | D
F | E
然后您可以使用此WITH RECURSIVE
查询来查找周期:
WITH RECURSIVE working(parent, last_visited, already_visited, cycle_detected) AS (
SELECT parent, child, ARRAY[parent], false FROM t
UNION ALL
SELECT t.parent, t.child, already_visited || t.parent, t.parent = ANY(already_visited)
FROM t
JOIN working ON working.last_visited = t.parent
WHERE NOT cycle_detected
)
SELECT parent, already_visited FROM working WHERE cycle_detected
它将为您提供属于周期的parent
以及它们所处的周期:
A | A,C,B,A
B | B,A,C,B
C | C,B,A,C
它的工作原理如下(因为这是关键字RECURSIVE
指示Postgres做的事情):
SELECT
,选择表t
中的所有条目,并将它们放在名为working
的临时表中。SELECT
,将working
表加入表t
以查找每个条目的子项。这些孩子被添加到已见过的孩子们中。SELECT
,只要将条目添加到working
表中。t.parent = ANY(already_visited)
)时,会检测到一个周期,在这种情况下cycle_detected
设置为true,并且不再向该条目添加子项。< / LI>
醇>
答案 2 :(得分:0)
您的任务中的表之间存在非常奇怪的引用。然而,这是我检查现有循环的方法。
table1的示例:
CREATE OR REPLACE FUNCTION fn_table1_check() RETURNS trigger
LANGUAGE plpgsql
AS $$
DECLARE
BEGIN
PERFORM 1 FROM table2
JOIN table3 ON table3.parent=table2.child
WHERE table2.parent=NEW.child AND table3.child=NEW.parent
LIMIT 1;
IF FOUND THEN
RAISE EXCEPTION 'Found recursive loop!';
END IF;
RETURN NEW;
END;
$$;
CREATE TRIGGER tg_table1_check BEFORE INSERT OR UPDATE ON table1 FOR EACH ROW EXECUTE PROCEDURE fn_table1_check();