我有一个输入数据,包括ID,prev,current和next节点(未排序)。 我必须在每个ID的第一页和最后一页之间找到一条路径,该路径覆盖所有遍历的节点。 例如:如果我的输入数据如下: 第一列是ID,第二列是prev_node,第三列是当前节点,第四列是下一个节点。 对于起始值,Prev_node将为空,而对于最后一个值
,下一个节点将为空输入
id prev current next 1 a b c 1 a e f 1 a b g 1 a b o 1 b c d 1 b g h 1 b o p 1 c d a 1 c b g 1 d a e 1 e f e 1 e f f 1 f e f 1 f f f 1 f f a 1 f a b 1 g h i 1 h i j 1 h j i 1 i j i 1 i i k 1 i k l 1 j i i 1 k l m 1 l m n 1 l n a 1 m n a 1 n a b 1 o p q 1 p q r 1 q r s 1 r s t 1 s t u 1 t u v 1 u v w 1 v w x 1 w x 1 a b
输出应该是当前节点的路径,如 -
ID current 1 a 1 b 1 c 1 d 1 a 1 e 1 f 1 e 1 f 1 f 1 f 1 a 1 b 1 b 1 g 1 h 1 i 1 j 1 j 1 i 1 i 1 k 1 l 1 m 1 n 1 n 1 a 1 b 1 o 1 p 1 q 1 r 1 s 1 t 1 u 1 v 1 w 1 x
这里会有很多具有相似数据的ID我只显示了一个ID(1)。另外在这里我使用的字母实际上是200-500个字符长的字符串。我尝试了几乎没有修改的SQL方法,如果一个ID有100行或者以下的行,它可以正常工作,但是对于更多行(即使将长字符串转换为数字后)也会产生字符串连接错误。任何人都可以建议一个强大的基于过程的方法相同。我尝试了一些,但它不适用于ID超过300行 我在下面的代码中遇到的错误是“字符串连接的结果太长”
我的代码
create or replace procedure pathing
as
type varr is table of varchar(4000);
visit varr;
t number;
--v varchar2(40);
fp varchar2(1000);
np varchar2(1000);
type stype is record(fp varchar2(1000),np varchar2(1000),t number);
type sinput is table of stype;
iarray sinput;
begin
select id
bulk collect into visit
from table_source
group by id
order by count(1) desc;
delete from table_final;
commit;
for k in visit.first .. visit.last loop
delete from table_temp;
commit;
insert into table_temp
select distinct prev_pg, page_id, next_pg, visit(k)
from table_source
where visit_id = visit(k)
order by prev_pg desc;
commit;
insert into table_final
WITH t_n AS (
SELECT prev_pg, page_id, next_pg, rownum n FROM table_temp
),
t_br AS (
SELECT
prev_pg,
page_id,
'<' || listagg(n, '|<') within GROUP(ORDER BY n) || '|' br,
COUNT(0) cnt
FROM
t_n
GROUP BY
prev_pg, page_id
),
t_mp AS (
SELECT
'|' || listagg(list) within GROUP(ORDER BY NULL) list
FROM (
SELECT REPLACE(br, '<') list FROM t_br WHERE cnt > 1
)
),
t_path(step, page_id, next_pg, used) AS (
SELECT 1, page_id, next_pg, ''
FROM t_n
WHERE prev_pg is null
UNION ALL
SELECT
step + 1,
t_br.page_id,
t_n.next_pg,
CASE
WHEN instr(list, '|' || n || '|') = 0
THEN used
ELSE used || n || '|'
END
FROM
t_mp,
t_path
JOIN t_br
ON next_pg = t_br.page_id AND t_path.page_id = prev_pg
JOIN t_n
ON n = regexp_substr(br, '^(<(' || used || '0)\|)*(<(\d+))?', 1, 1, '', 4)
) cycle step
SET is_cycle TO 'Y' DEFAULT 'N'
SELECT
page_id,
next_pg,
step,
visit(k)
FROM t_path
ORDER BY 1;
commit;
end loop;
end;
进一步解释我的例子: - 我想要每个ID的完整路径旅程,在示例中我以ID 1为例。对于ID 1,我们有一组当前值,上一个和下一个值。所以我们需要使用这些值找到路径。例如,对于id 1,路径以'a'开头,因为prev列为空。然后我们看到a的下一个值是b,即current是a,next是b所以我们在id的所有行中搜索prev值作为a,当前值作为b,在我们找到相同的点我们采取下一个行的值并重复该过程。例如,在这里上一个,当前的b和下一个是c所以我们再次搜索prev b和当前c等等,直到我们得到完整的路径,直到我们遇到下一个为null,因为它将是最后一个
答案 0 :(得分:3)
通过Hierarchical查询子句的解决方案似乎很棘手,但应该有一个解决方案,仍然可以使用现有的PL / SQL代码,但将VARCHAR字段更改为CLOB以避免“字符串连接的结果太长”
答案 1 :(得分:2)
您可以在程序中使用以下查询来完成目标
select id,current into v_your_output_collection from nodes
where id = :vId
start with prev_node is null
connect by
NOCYCLE
prior next_node= current and prior current = prev_node
适用于Oracle 10g及更高版本