Sql Oracle:分层查询中的编号组

Sql Oracle:分层查询中的编号组,sql,database,oracle,hierarchical-data,recursive-query,Sql,Database,Oracle,Hierarchical Data,Recursive Query,在我的OracleDB中,我有一个表定义了一个前辈/后辈的层次结构,它可以进行分支和循环。我附带了一个SQL提琴来演示这个表是如何工作的。我的意图是给每棵孤立的树分配它自己的编号。关于预期结果的解释,请参见下图(请注意,在这张图中,成员被命名为a、b、c、d…而在所附的提琴中,他们被编号为1,2,3,4): 我还没有弄明白如何构建这样一个查询,而此时此刻我几乎绝望了。 任何帮助,甚至是指向解决方案的指针——任何类型的输入——都将不胜感激 提前感谢大家。我的理解是,对于每个根节点,您需要为其分

在我的OracleDB中,我有一个表定义了一个前辈/后辈的层次结构,它可以进行分支和循环。我附带了一个SQL提琴来演示这个表是如何工作的。我的意图是给每棵孤立的树分配它自己的编号。关于预期结果的解释,请参见下图(请注意,在这张图中,成员被命名为a、b、c、d…而在所附的提琴中,他们被编号为1,2,3,4):

我还没有弄明白如何构建这样一个查询,而此时此刻我几乎绝望了。 任何帮助,甚至是指向解决方案的指针——任何类型的输入——都将不胜感激


提前感谢大家。

我的理解是,对于每个根节点,您需要为其分配一个组号。为了找到根节点,我们可以使用
connect\u by\u root
,然后我们可以使用densite\u rank给它一个数字

到目前为止,我得到了这个,你能检查一下吗


免责声明:此解决方案适用于PostgreSQL,而不是Oracle。

下面的查询演示了一种解决为每个子图分配唯一序列号问题的策略

注意:我试图为Oracle编写查询,但似乎XMLTable()函数有缺陷。如果你能找到一个解决办法,也许你可以将它应用到Oracle(我放弃了)

结果:

node  g
----  -
a     1
b     1
c     1
d     1
e     1
f     2
g     2
h     2
i     3
j     3

参见运行示例。

这些不是层次结构;它们是有向图。您仍然可以在Oracle中使用
connectby
来使用它们,但是如果没有根节点以
开头,那么如果您的数据集很大,性能可能会有问题

无论如何,您需要做的是通过NOCYCLE连接
,而无需使用
开始
。它将从每个单独的节点开始计算一棵树。然后,获取每个节点的
connectby\u ROOT
,并获取每个不同节点的
MIN()

下面是一个工作示例,其中包含数据。它比需要的更复杂,因为没有地方可以获得所有节点的完整列表,所以您必须将每个顶点拆分为两行(一行具有from_节点,另一行具有to_节点),以确保包含所有节点

CREATE TABLE tbl_tst ( from_node VARCHAR2(1), to_node VARCHAR2(1) );

INSERT INTO tbl_tst VALUES ( 'a', 'b');
INSERT INTO tbl_tst VALUES ( 'b', 'c');
INSERT INTO tbl_tst VALUES ( 'b', 'd');
INSERT INTO tbl_tst VALUES ( 'd', 'a');
INSERT INTO tbl_tst VALUES ( 'd', 'e');

INSERT INTO tbl_tst VALUES ( 'f', 'g');
INSERT INTO tbl_tst VALUES ( 'g', 'h');
INSERT INTO tbl_tst VALUES ( 'h', 'f');

INSERT INTO tbl_tst VALUES ( 'i', 'j');

COMMIT;


WITH groups AS (
SELECT DISTINCT 
       tt.from_node, 
       tt.to_node, 
       MIN(CONNECT_BY_ROOT(from_node)) 
             OVER ( PARTITION BY tt.from_node) group_min
FROM   tbl_tst tt
CONNECT BY NOCYCLE from_node = PRIOR to_node
              OR   to_node = PRIOR from_node
)
SELECT DENSE_RANK() OVER ( ORDER BY group_min ) group_number,
       DECODE(splitter.rn,1,groups.from_node,2,groups.to_node) node       
FROM groups 
CROSS JOIN ( SELECT rownum rn FROM dual CONNECT BY rownum <= 2 ) splitter
GROUP BY DECODE(splitter.rn,1,groups.from_node,2,groups.to_node),
         group_min
ORDER BY group_min, node;

我无法理解您希望如何从fiddle链接输出结果。你能添加你的预期结果吗?@Sujitmohanty30,小提琴并不能准确地解释预期的输出。由于这个确切的原因,该图表被包括在问题中。但是,我添加了第二张图片,以表格形式演示我所需的输出,这将更容易理解。谢谢你的意见。不完全是这样,尽管这已经很接近了。小提琴中的组号1、2、3应该都是组号=1,因为它们之间有联系。路径/1/3/2与路径/2/1/3或/3/2/1是同一棵树的一部分。因此,他们都应该有相同的组号。明白你的意思。这里需要一些分析。尝试了一些变化,但没有运气>代码>从.No.No.=以前的节点No/<代码> -可能更改为<代码> FaseNo结=PrimetoOnEngor或ToObjeNo.=之前从节点No./CODE >,因为您不需要考虑图的弧的方向。此更改可以更快地遍历子图,生成更少的分支,并提高性能。好。。。“只要我能很好地理解您的解决方案。”在第一个CTE中实际生成更多行的编译器。通过
条件扩展
连接会增加连接,而不是减少连接。@我的同事,但我刚刚意识到,如果你有一行,比如“m->h”,我的解决方案就不起作用了。因此,我认为我需要您的更改,以在所有情况下获得正确的结果。谢谢。你的解决方案比我的要简洁得多。另外,它在Oracle中也可以工作+神圣的烟。这很好用。我会花一些时间来分析你的解决方案和具体的内部运作,但奖金肯定是你的。1小时后我才能奖励它。脱帽致敬——同时,感谢你给我一个指针,让我找到更多关于这个问题的信息。知道它的名称将帮助我深入了解它。
node  g
----  -
a     1
b     1
c     1
d     1
e     1
f     2
g     2
h     2
i     3
j     3
CREATE TABLE tbl_tst ( from_node VARCHAR2(1), to_node VARCHAR2(1) );

INSERT INTO tbl_tst VALUES ( 'a', 'b');
INSERT INTO tbl_tst VALUES ( 'b', 'c');
INSERT INTO tbl_tst VALUES ( 'b', 'd');
INSERT INTO tbl_tst VALUES ( 'd', 'a');
INSERT INTO tbl_tst VALUES ( 'd', 'e');

INSERT INTO tbl_tst VALUES ( 'f', 'g');
INSERT INTO tbl_tst VALUES ( 'g', 'h');
INSERT INTO tbl_tst VALUES ( 'h', 'f');

INSERT INTO tbl_tst VALUES ( 'i', 'j');

COMMIT;


WITH groups AS (
SELECT DISTINCT 
       tt.from_node, 
       tt.to_node, 
       MIN(CONNECT_BY_ROOT(from_node)) 
             OVER ( PARTITION BY tt.from_node) group_min
FROM   tbl_tst tt
CONNECT BY NOCYCLE from_node = PRIOR to_node
              OR   to_node = PRIOR from_node
)
SELECT DENSE_RANK() OVER ( ORDER BY group_min ) group_number,
       DECODE(splitter.rn,1,groups.from_node,2,groups.to_node) node       
FROM groups 
CROSS JOIN ( SELECT rownum rn FROM dual CONNECT BY rownum <= 2 ) splitter
GROUP BY DECODE(splitter.rn,1,groups.from_node,2,groups.to_node),
         group_min
ORDER BY group_min, node;
+--------------+------+
| GROUP_NUMBER | NODE |
+--------------+------+
|            1 | a    |
|            1 | b    |
|            1 | c    |
|            1 | d    |
|            1 | e    |
|            2 | f    |
|            2 | g    |
|            2 | h    |
|            3 | i    |
|            3 | j    |
+--------------+------+