10

我有一个输入数据,其中包含 ID、上一个、当前和下一个节点(未排序)。我必须在每个 ID 的第一页和最后一页之间找到一条路径,该路径涵盖了遍历的所有节点。例如:如果我的输入数据是这样的:第一列是 ID,第二列是 prev_node,第三列是当前节点,第四列是下一个节点。Prev_node 将是空的起始值,下一个节点将是空的最后一个值

输入

id 上一个 当前下一个
1个ABC
1个
1个
1个
1 bcd
1 bgh
1 个
1 光盘
1 cbg
1代
1个
1 效
1个
1个
1个
1 个晶圆厂
1吉
1 个
1个
1 伊吉
1个
1 公斤
1个
1 公里
1 分钟
1个lna
1 mna
1个
1个操作
1 份
1 qrs
第一个
1个
1 台
1 紫外线
1个
1个
1个抗体

输出应该是当前节点的路径,例如 -

识别电流
1个
1个
1摄氏度
1天
1个
1e
1 英尺
1e
1 英尺
1 英尺
1 英尺
1个
1个
1个
1克
1小时
1 我
1j
1j
1 我
1 我
1千
1升
1米
1个
1个
1个
1个
1个
1个
1个
1r
1 秒
1吨
1个
1 伏
1 瓦
1 个

这里会有许多具有相似数据的 ID,我只显示了一个 ID(1)。同样在这里,我使用了实际上是 200-500 个字符长的字符串的字母。我尝试了几乎没有修改的 SQL 方法,如果 ID 的行数为 100 或以下,但它会为更多行提供字符串连接错误(即使在将长字符串转换为数字之后)。任何人都可以建议一种基于稳健程序的方法。我尝试了一些,但它不适用于超过 300 行的 ID。
我有时遇到以下代码的错误是“字符串连接的结果太长”

我的代码

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 即当前是 a 并且下一个是 b 所以我们在 id 1 的所有行中搜索上一个值作为 a 和当前值作为 b ,在这一点上我们找到相同的我们取下一个行的值并重复该过程。例如这里 prev a ,current b 和 next 是 c 所以我们再次搜索 prev b 和 current c 等等,直到我们得到完整路径,直到我们遇到 next as null 因为那将是最后一个

4

2 回答 2

3

通过分层查询子句的解决方案似乎很棘手,但应该有一个解决方案,仍然作为替代方案,使用您现有的 PL/SQL 代码但将 VARCHAR 字段更改为 CLOB 以避免“字符串连接的结果太长”。

于 2013-10-31T09:35:50.123 回答
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 及更高版本

于 2013-10-29T19:11:59.080 回答