Received: from maia.hub.org (unknown [200.46.208.211]) by mail.postgresql.org (Postfix) with ESMTP id 6A0D265B286 for ; Tue, 16 Mar 2010 17:05:49 -0300 (ADT) Received: from mail.postgresql.org ([200.46.204.86]) by maia.hub.org (mx1.hub.org [200.46.208.211]) (amavisd-maia, port 10024) with ESMTP id 12379-01-2 for ; Tue, 16 Mar 2010 20:05:34 +0000 (UTC) X-Greylist: delayed 00:19:18.360989 by SQLgrey-1.7.6 Received: from shetland.sei.cmu.edu (shetland.sei.cmu.edu [192.58.107.44]) by mail.postgresql.org (Postfix) with ESMTP id C5AC765B36B for ; Tue, 16 Mar 2010 17:04:56 -0300 (ADT) Received: from ms02.sei.cmu.edu (ms02.sei.cmu.edu [128.237.22.38]) by shetland.sei.cmu.edu (8.13.8/8.13.8/1294) with ESMTP id o2GJja92002493 for ; Tue, 16 Mar 2010 15:45:36 -0400 Received: from lisa.yellow.cert.org (lisa.yellow.cert.org [10.20.10.153]) by ms02.sei.cmu.edu (8.13.1/8.13.1/1295) with ESMTP id o2GJjZuP024597 for ; Tue, 16 Mar 2010 15:45:36 -0400 Message-ID: <4B9FDFDE.5030005@andrew.cmu.edu> Date: Tue, 16 Mar 2010 15:45:34 -0400 From: Tony Cebzanov User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1.8) Gecko/20100227 Thunderbird/3.0.3 Mnenhy/0.7.6.0 MIME-Version: 1.0 To: pgsql-sql@postgresql.org Subject: Avoiding cycles in a directed graph Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit X-Virus-Scanned: Maia Mailguard 1.0.1 X-Spam-Status: No, hits=-2.599 tagged_above=-10 required=5 tests=BAYES_00=-2.599 X-Spam-Level: X-Archive-Number: 201003/109 X-Sequence-Number: 33816 I'm using the following table to represent an acyclic directed graph: CREATE TABLE edge( id SERIAL PRIMARY KEY, child INTEGER NOT NULL, parent INTEGER, UNIQUE (child, parent) ); I see there is an example in the online docs for detecting cycles in recursive queries, and I've adapted the example query to the table above: WITH RECURSIVE search_graph(parent, child, id, depth, path, cycle) AS ( SELECT e.parent, e.child, e.id, 1, ARRAY[e.id], false FROM edge e UNION ALL SELECT e.parent, e.child, e.id, sg.depth + 1, path || e.id, e.id = ANY(path) FROM edge e, search_graph sg WHERE e.parent = sg.child AND NOT cycle ) SELECT * FROM search_graph; That's great to avoid looping forever on queries, but what about preventing anyone from inserting edges that would create cycles in the first place? I reckon I'll need a trigger of some sort, but nothing I've tried has enabled me to do the cycle check as part of the trigger to avoid inserting an edge that would create a cycle. I tried having the non-recursive SELECT use NEW.parent, NEW.child, etc. but that isn't working. Is there any way to do this, or do I have to just insert the edge, check if it cycles, and delete it if it does? Thanks. -Tony