我还是oracle的新手,我需要以下方面的帮助:
让我们说我有一个包含节点的表:
DECLARE @nodes TABLE (node VARCHAR(5))
INSERT INTO @nodes
VALUES
('A'),
('B'),
('C'),
('D')
以及包含这些节点如何连接在一起的表格:
DECLARE @connected_nodes TABLE (node_1 VARCHAR(5),node_2 VARCHAR(5))
INSERT INTO @connected_nodes
VALUES
('A','B'),
('B','C'),
('A','C'),
('C','D')
我需要在oracle中编写一个程序,找到两个节点之间的路径,这意味着,例如,如果我想从A到C,我在上面的例子中有两个路径: A - &以及c A - B - &以及c 所以程序必须返回这两个路径以及跳数(在这种情况下,第一个路径为1,第二个路径为2)
注意到存在数百/数千个节点。
非常感谢您的帮助
答案 0 :(得分:1)
请注意,您不能像在SQL SERVER中那样在Oracle中使用DECLARE @connected_nodes TABLE
。您需要创建一个表并将记录插入表中。
使用此分层查询可以实现您需要显示的输出。
select LTRIM ( SYS_CONNECT_BY_PATH ( node_1,'->' ) ,'->')as paths
, LEVEL-1 as number_of_hops
FROM connected_nodes WHERE LEVEL > 1
CONNECT BY NOCYCLE PRIOR node_2 = node_1
;
以下是所有步骤的完整演示。
编辑::如果您只需要查找特定节点之间的路径(A-> C),请使用 附加条件。
select LTRIM ( SYS_CONNECT_BY_PATH ( node_1,'->' ) ,'->')as paths
, LEVEL-1 as number_of_hops
FROM connected_nodes WHERE
node_1 = 'C'
START WITH node_1 = 'A'
CONNECT BY NOCYCLE PRIOR node_2 = node_1
;
答案 1 :(得分:1)
您需要一个分层查询来获得所需的结果,应用一些逻辑来仅获取从给定值到另一个值的路径:
with nodes (node) as (
select 'A' from dual union all
select 'B' from dual union all
select 'C' from dual union all
select 'D' from dual
),
connected_nodes (node_1,node_2 ) as
(
select 'A','B' from dual union all
select 'B','C' from dual union all
select 'B','D' from dual union all
select 'A','C' from dual union all
select 'A','D' from dual union all
select 'D','C' from dual union all
select 'C','D' from dual
)
select ltrim(sys_connect_by_path(node_1, '->'), '->') as path,
level -1 as hops
from
(
select node as node_1, node_2
from nodes
left join connected_nodes
on(node = node_1)
)
where node_1 = 'C' /* where to stop */
connect by nocycle prior node_2 = node_1
and prior node_1 is not null
start with node_1 = 'A' /* where to start from */;
给出:
PATH HOPS
---------- ----------
A->B->C 2
A->B->D->C 3
A->C 1
A->D->C 2
答案 2 :(得分:0)
这可能是一种没有分层查询的方法。 他们让我头疼。
drop table connected_nodes;
create table connected_nodes (node_1 VARCHAR2(5),node_2 VARCHAR2(5));
INSERT INTO connected_nodes VALUES('A','B');
INSERT INTO connected_nodes VALUES('B','A');
INSERT INTO connected_nodes VALUES('B','C');
INSERT INTO connected_nodes VALUES('A','C');
INSERT INTO connected_nodes VALUES('C','D');
commit;
drop table links;
create table links
(from_node_1 VARCHAR2(5),
from_node_2 VARCHAR2(5),
to_node_1 VARCHAR2(5),
to_node_2 VARCHAR2(5),
first_node_1 VARCHAR2(5),
first_node_2 VARCHAR2(5),
link_num NUMBER);
drop table paths;
create table paths as select * from links;
create or replace procedure get_paths(p_node_1 VARCHAR2,p_node_2 VARCHAR2)
as
prev_num_links number;
num_links number;
begin
-- get first links in paths
insert into links
select
NULL,
NULL,
cn.node_1,
cn.node_2,
cn.node_1,
cn.node_2,
1
from
connected_nodes cn
where
cn.node_1 = p_node_1;
-- loop until number of path links does not increase
prev_num_links := 0;
loop
select count(*) into num_links from links;
if num_links = prev_num_links then
exit;
end if;
-- add new links
insert into links
select
l.to_node_1,
l.to_node_2,
c.node_1,
c.node_2,
l.first_node_1,
l.first_node_2,
l.link_num+1
from connected_nodes c,links l
where
l.to_node_2 = c.node_1 and
l.to_node_2 <> p_node_2 and
(l.to_node_1,
l.to_node_2,
c.node_1,
c.node_2) not in
(select
from_node_1,
from_node_2,
to_node_1,
to_node_2
from links);
commit;
prev_num_links := num_links;
end loop;
-- populate paths table with links that go backward
-- from end node to beginning.
-- add end nodes
insert into paths
select * from links
where to_node_2 = p_node_2;
-- loop until number of paths rows does not increase
prev_num_links := 0;
loop
select count(*) into num_links from paths;
if num_links = prev_num_links then
exit;
end if;
-- add new links
insert into paths
select
*
from links l
where
(l.to_node_1,
l.to_node_2,
l.first_node_1,
l.first_node_2,
l.link_num+1)
in
(select
from_node_1,
from_node_2,
first_node_1,
first_node_2,
link_num
from paths) and
(l.from_node_1,
l.from_node_2,
l.to_node_1,
l.to_node_2,
l.first_node_1,
l.first_node_2,
l.link_num)
not in
(select * from paths);
commit;
prev_num_links := num_links;
end loop;
end;
/
show errors
execute get_paths('A','C');
select
to_node_1,to_node_2,link_num,first_node_1,first_node_2
from paths
order by first_node_1,first_node_2,link_num;
输出如下:
TO_NO TO_NO LINK_NUM FIRST FIRST
----- ----- ---------- ----- -----
A B 1 A B
B C 2 A B
A C 1 A C
列first_node_1和first_node_2 定义路径和link_num列 是它在路径中的链接。
超长而且凌乱。可能是我没有处理的案件。 我想除非你不能使用分层查询。这是一 尝试在没有它们的情况下使用SQL和PL / SQL。