PL / SQL中的递归

Whizzyifti

我的任务是在n个集合中进行元素组合。这样一个集合中的任何元素都不会与自身结合。结构为:

产品--->控件---> LOV [值列表]

示例场景:

1产品->具有3个控件1->具有3个LOV控件2->具有2个LOV控件3->具有5个LOV

产品1的可能组合编号:3 * 2 * 5 = 30。

作为一名程序员和SQL的新手,我立即求助于递归。我不知道PL / SQL中递归的效率。但是我通过遍历所有控件(如树)并在叶子处拾取值来获得所需的结果。该解决方案有效,但是如果要在不进行递归的情况下进行,可能的方法是什么?

procedure postcombinations(pProductID in varchar2,
                           lovs       in varchar2,
                           ctrl       in varchar2) is
  lv_cp varchar2(100);
  lv_cl varchar2(100);
begin

  -- Loop through All the controls defined against a product other
  -- than the ones already traversed (Not in condition) also 
  -- restrict results to One branch since order is doesn't matter.

  for i in (select cp.control_id
              from tbl_control_product cp, tbl_control c
             where cp.product_id = pProductID
               and cp.control_id = c.control_id
               and c.control_type = 2
               and cp.control_id not in
                   (select regexp_substr(ctrl, '[^,]+', 1, level)
                      from dual
                    connect by regexp_substr(ctrl, '[^,]+', 1, level) is not null)
               and rownum < 2) loop
    begin

      -- Loop through all the LOV's in the controls and append them to Input 
      --to recurse the function 
      for p in (select cl.lov_id
                  from tbl_control_lov cl
                 where cl.control_id = i.control_id) loop
        if lovs is not null then
          pkg_product.postcombinations(pProductID => pProductID,
                                       lovs       => lovs || ',' ||
                                                     p.lov_id,
                                       ctrl       => ctrl || ',' ||
                                                     i.control_id);
        else
          pkg_product.postcombinations(pProductID => pProductID,
                                       lovs       => lovs,
                                       ctrl       => ctrl || ',' ||
                                                     i.control_id);
        end if;

      end loop;
    end;
  end loop;

  -- When A leaf is encountered the select statement returns a null 
  --the inputs are dumped into a table and voila.
  begin
    select cp.control_id
      into lv_cp

      from tbl_control_product cp, tbl_control tc
     where cp.product_id = pProductID
       and cp.control_id = tc.control_id
       and tc.control_type = 2
       and cp.control_id not in
           (select regexp_substr(ctrl, '[^,]+', 1, level)
              from dual
            connect by regexp_substr(ctrl, '[^,]+', 1, level) is not null)
       and rownum < 2;
  Exception
    When NO_DATA_FOUND then
      insert into tbl_test values (ctrl, lovs);
      commit;
  end;

end;
亚历克斯·普尔

尚不清楚您在做什么,但这将为您提供30种组合control_idlov_id单个产品的组合

select tcp.control_id, tcl.lov_id
from tbl_control_product tcp
join tbl_control tc on tc.control_id = tcp.control_id
cross join tbl_control_lov tcl
where tcp.product_id = <productID>
and tc.control_type = 2;

三个控件中的每个控件都可以看到任何一个的10个LOV。

但是从我认为您的程序正在执行的操作来看,如果要针对产品列出三个控件,则要列出这些控件以及它们下面的LOV的所有组合。您的过程似乎存在错误else-我认为您需要lovs => p.lov_id在那里,而不是lovs => lovs; 有了那个改变,最初的通话就可以了lovs => null但是您似乎必须传递的初始数字ctrls,这会破坏输出。如果我遵循它并正确地创建了数据(请参见下面的小提琴),那么最终会插入这样的内容(如果称为)pkg_product.postcombinations(pProductID => 'ABC', lovs => null, ctrl => '0')

ctrl 0,11,12,13 lovs 101,201,301
ctrl 0,11,12,13 lovs 101,201,302
ctrl 0,11,12,13 lovs 101,201,303
...
ctrl 0,11,12,13 lovs 103,202,304
ctrl 0,11,12,13 lovs 103,202,305

如果这是正确的,则只要使用11gR2(因为它使用递归子查询因子),您就可以使用单个SQL语句执行相同的操作:

with t as (
  select tcp.control_id, tcl.lov_id,
    dense_rank() over (partition by tcp.product_id
      order by tcp.control_id) as control_num,
    count(distinct tcp.control_id)
      over (partition by tcp.product_id) as control_count
  from tbl_control_product tcp
  join tbl_control tc on tc.control_id = tcp.control_id
  join tbl_control_lov tcl on tcl.control_id = tc.control_id
  where tcp.product_id = 'ABC'
  and tc.control_type = 2
),
r (control_num, control_count, ctrl, lovs) as (
  select control_num, control_count, to_char(control_id), to_char(lov_id)
  from t
  where control_num = 1
  union all
  select t.control_num, t.control_count,
    ctrl ||','|| control_id, lovs ||','|| lov_id
  from r
  join t on t.control_num = r.control_num + 1
)
select ctrl, lovs
from r
where control_num = control_count
order by ctrl, lovs;

有点类似于您正在使用的逻辑。这给出了:

CTRL                 LOVS               
-------------------- --------------------
11,12,13             101,201,301          
11,12,13             101,201,302          
11,12,13             101,201,303          
...
11,12,13             103,202,304          
11,12,13             103,202,305  

SQL小提琴

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章