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

发布于 2024-08-12 07:10:33 字数 1435 浏览 3 评论 0原文

我的日期是按树形结构组织的。

以下适用(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

My date is organized in tree structure.

The following applies (Oracle SQL syntax):

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');

I would like to return full tree by id, so for query :

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

I would get

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

for a sub tree I would get:

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

I would get

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

Where as, for flat entry b, it would get

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

I would get

|  name  |  id  |
|  b     |  6   |

It seems that plain left out join queries fails to fulfill this purpose, or am I missing something?

The following query does return the full structure, but when starting to filter with where statements it fails.

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

唐婉 2024-08-19 07:10:33

当您具有树结构时,您可能需要分层查询。如下:

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

请参阅分层查询 了解详情。

When you have a tree structure, you likely need a hierarchical query. Here it is:

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

See Hierarchical Queries for details.

爱人如己 2024-08-19 07:10:33

您可以在 Oracle 上使用 start with - connect by 语法。如果我没记错的话,事情是这样的

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

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

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

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

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

You can use start with - connect by syntax on Oracle. If I'm not mistaken, it goes like this

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

But I have no Oracle to check it right away. Maybe its prior t.Parent = t.ID. Beware that it can be slow sometimes, use with caution.

Alternative is to create table to store all indirect relationship between nodes (not just a-a.1, but also a-a.2.1 and so on). You can fill it using PL/SQL recursive stored procedure. Two ways:

  1. Simple way is to make a procedure that will do complete refill of indirect table. You can call it before running reports.

  2. If you need instant effects, you should write refill procedure so that it will update indirect relationship just for one record in tree. Then you prohibit direct inserts and updates to Tree and force them to go via stored PL/SQL procedures (like InsertTree/UpdateTree) which in turn will call procedure to update table with indirect relationships.

七婞 2024-08-19 07:10:33

为此,您可以使用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 扩展(如果有任何可用的内容)。

You could use union for this, and you need to limit the depth of the tree to make it possible to select it in one query.

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

The problem here is, SQL is very bad in recursion (while relational structures are actually great in this).

To make it fully dynamic, use a query for each level in the tree, or use a database engine specific SQL extension if there is anything usable.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文