同一个表上的嵌套连接(树结构)

时间:2009-11-23 10:55:29

标签: sql oracle tree hierarchy

我的日期以树形结构组织。

以下内容适用(Oracle SQL语法):

CREATE TABLE TREE
(
  NAME VARCHAR2(20),
  ID NUMBER(10, 0),
  PARENT NUMBER(10, 0)
)
;

INSERT INTO "TREE" (NAME, ID) VALUES ('a', '1');
INSERT INTO "TREE" (NAME, ID, PARENT) VALUES ('a.1', '2', '1');
INSERT INTO "TREE" (NAME, ID, PARENT) VALUES ('a.2', '3', '1');
INSERT INTO "TREE" (NAME, ID, PARENT) VALUES ('a.2.1', '4', '3');
INSERT INTO "TREE" (NAME, ID, PARENT) VALUES ('a.2.2', '5', '3');
INSERT INTO "TREE" (NAME, ID) VALUES ('b', '6');

我想通过id返回完整的树,所以对于查询:

select name, id <<<TODO LOGIC>> where id = 1

我会得到

|  name  |  id  |
|  a     |  1   |
|  a.1   |  2   |
|  a.2   |  3   |
|  a.2.1 |  4   |
|  a.2.2 |  5   |

我会得到一个子树:

select name, id <<<TODO LOGIC>> where id = 3

我会得到

|  name  |  id  |
|  a.2   |  3   |
|  a.2.1 |  4   |
|  a.2.2 |  5   |

对于平面入口b,它将得到

select name, id <<<TODO LOGIC>> where id = 6

我会得到

|  name  |  id  |
|  b     |  6   |

似乎简单的遗漏联接查询无法实现此目的,或者我错过了什么?

以下查询确实返回完整结构,但在开始使用 where 语句进行过滤时,它会失败。

select t1.id t1Id, t2.id t2Id, t1.name t1Name, t2.name t2Name from tree t1 left outer join tree t2 on t1.id = t2.parent

3 个答案:

答案 0 :(得分:3)

如果您有树结构,则可能需要分层查询。这是:

 select t.*
   from tree t
connect by prior t.id = t.parent
  start with t.id = :id
  order siblings by t.id

有关详细信息,请参阅Hierarchical Queries

答案 1 :(得分:2)

您可以在Oracle上使用start with - connect by语法。如果我没弄错的话,就像这样

select * from Tree t
start with t.ID = 1 connect by prior t.ID = t.Parent

但是我没有Oracle立即检查它。也许是prior t.Parent = t.ID。请注意,有时可能会很慢,请谨慎使用。

替代方法是创建表来存储节点之间的所有间接关系(不仅仅是a-a.1,还有a-a.2.1等)。您可以使用PL / SQL递归存储过程填充它。两种方式:

  1. 简单的方法是制作一个完成间接表填充的程序。您可以在运行报告之前调用它。

  2. 如果您需要即时效果,则应编写重新填充程序,以便仅为树中的一条记录更新间接关系。然后禁止直接插入和更新Tree并强制它们通过存储的PL / SQL过程(如InsertTree / UpdateTree)进行,这些过程将调用过程以间接关系更新表。

答案 2 :(得分:0)

您可以使用union,并且您需要限制树的深度,以便可以在一个查询中选择它。

SELECT id, name
FROM TREE as node
WHERE 
  node.id = :id
UNION
SELECT child1.id, child1.name
FROM TREE as node
  inner join TREE as child1 on node.id = child1.parent
WHERE 
  node.id = :id
UNION
SELECT child2.id, child2.name
FROM TREE as node
  inner join TREE as child1 on node.id = child1.parent
  inner join TREE as child2 on child1.id = child2.parent
WHERE 
  node.id = :id

这里的问题是,SQL在递归方面非常糟糕(虽然关系结构实际上非常好)。

要使其完全动态化,请对树中的每个级别使用查询,或者如果有任何可用的话,请使用特定于数据库引擎的SQL扩展。