我的任务是在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;
答案 0 :(得分:1)
目前还不完全清楚您正在做什么,但这会为您提供单个产品的control_id
和lov_id
的30种组合:
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
如果这是正确的,那么你可以用一个SQL语句做同样的事情,只要你使用11gR2,因为它使用递归子查询因子分析:
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