2012-03-09 10 views
3

我有以下DAG在关闭工作台移动与多亲

A --> B 

|  | 
v  v 

C --> D 

这里是封闭表

| Ancestor | Descendant | Depth | 
--------------------------------- 
| A  | A   | 0  | 
| A  | B   | 1  | 
| A  | C   | 1  | 
| A  | D   | 2  | 
| A  | D   | 2  | 
| B  | B   | 0  | 
| B  | D   | 1  | 
| C  | C   | 0  | 
| C  | D   | 1  | 
| D  | D   | 0  | 

我怎么会去不还删除删除路径B > D(从而消除A > B > DA > C > DC > D

现在我正在使用下面的查询,但它只适用于每个节点只有1个父项。

DELETE FROM `Closure` 
WHERE `Descendant` IN (SELECT `Descendant` FROM `Closure` WHERE `Ancestor`[email protected]) 
AND `Ancestor` NOT IN (SELECT `Descendant` FROM `Closure` WHERE `Ancestor`[email protected]); 

回答

1

在自然语言,这将是:“删除祖先子孙relashionship到d,如果没有,除了乙d的父母,这也是A的后裔”。那是对的吗?

编辑:不,那是不正确;不仅要relashionships d必须删除,而且也relashionships到d的每一个后代。因此,这个标准是无效的......)

然后我试探性的SQL是:

DELETE a 
FROM Closure AS a 
    INNER JOIN Closure AS b ON a.Descendant = b.Descendant 
WHERE 
    a.Descendant IN (SELECT Descendant FROM Closure WHERE Ancestor = {Child}) AND 
    b.Depth = 1 AND 
    b.Ancestor != {Parent} AND 
    a.Ancestor NOT IN (SELECT Ancestor FROM Closure WHERE Descendant = b.Ancestor) 

(很抱歉,如果我得到了查询错误 - 或使用非标准的特性 - 我没有真正与经历,但我的自然语言描述应该给一个什么样的见解实际上需要去查询)


更新:关于第二个想法,我不相信我的查询将所有的情况下工作。这样考虑:

A --> B --> D --> E --> F 
  1. F是d(真)的后代
  2. E是F(真)的父
  3. E不是B(真)
  4. A不是一个E的前身(假)

因此,A >> F将不会被删除,即使它应该。对不起,我忍不住,但这似乎是一个太大的问题,不适合单个查询。我建议先找一个算法解决方案,然后看看你的情况如何实现。

2

首先,我相信你的表中有重复的条目。 (A,D)出现两次。第二,在除去边缘(B,D)后,下面的路径应保持:

  1. 节点自映射:(A,A)(B,B)(C,C)(D,D)
  2. (A,B)
  3. (A,C)
  4. (A,D)(通过C)

因此,要删除此e中的边缘(B,D) xample,所需要的只是删除那一行:

Delete MyTable 
Where Ancestor = 'B' 
    And Descendant = 'D' 

闭包表仍然只是映射两个节点之间的关系。它的特殊之处在于它将每个间接关系有效地映射为一个直接的关系。边缘(B,D)只是说您可以从BD。该行本身并没有说明你如何得到B,也没有说明有多少节点从BD;它只是说你可以B得到D。因此,A > B > D本身没有列出的边缘。相反,所有被捕获的是,你可以从ABAD,即使边缘(B,D)被删除,这仍然是真实的。

+0

重复(A,D)实际上是这个问题的根源 - 它存在表明,在一个闭包表中,你将有一个(A,D)由ABD和ACD引起。如何检测另一条路径在此钻石中相交而不是删除(A,D)?最好只使用SQL并且只给出边(B,D)。 – NtscCobalt 2013-05-29 20:56:38

+0

@NtscCobalt - 在那里有两次'(A,D)'是没有意义的。闭包表不会描述*一个节点如何与另一个节点连接;只有*表示一个节点与另一个节点相连。因此,如果表中有((A,D)),从A到D的路径是否是A> B> C> E> .....> X > Y> D'或'A> D'。这才是重点。封闭表格为您节省了每次计算该路径的麻烦。如果您试图捕获从一个节点到另一个节点的路径,那么封闭表不是解决方案。而是将图形存储在边缘表中并计算路径。 – Thomas 2013-05-29 21:32:14

+0

啊,是啊,我很难记住为什么我问这个问题说实话。我不记得我们决定做什么解决方案。我认为最初的目的是找出一种从(B,D)中删除边缘的方法,并删除由此引起的闭合表中的所有条目,而不会意外删除仍然存在的边缘。我可以立即想到的唯一解决方案是从您只知道一步的节点重建整个闭合表。 – NtscCobalt 2013-05-29 21:35:35