求用SQL实现一个排列组合的算法题

ifvlr 2018-04-29 07:29:26
原始数据如图一


想得到图二的结果


简单来说,图一是要去做排列组合的基础的数据,基础数据只有1,2,3三个不同的值, 图二是图一通过排列组合后的最简结果,把里面能合并的数据合并,不能合并的数据继续用原始的数据写出来即可。。请问这个要如何实现。
如:
1 1 2 1
1 1 2 3
可以合并为
1 1 2 1,3


1 2 2 1
1 2 2 3
3 2 2 3
3 2 2 1
可以合并为
1,3 2 2 1,3

但是像原始数据
1 3 2 3
就没法和别的数据做排列组合的合并,那么在result表中就继续保留为
1 3 2 3

当然,我这只是部分数据,实际数据很多,可能最终result的结果在算法不同的情况下得到的排列组合方式也不一样,我希望能得到 select count(*) from t_sort_and_comb_result 的结果最小的算法为最优解。
请问这个如何实现。可以用SQL,循环,游标,存储过程等等方法,只要能得到最优的结果。
...全文
2655 7 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
nayi_224 2018-05-31
  • 打赏
  • 举报
回复
http://www.itpub.net/forum.php?mod=viewthread&tid=2102296 http://www.itpub.net/thread-1851315-1-2.html 好像跟这俩有点像
nayi_224 2018-05-31
  • 打赏
  • 举报
回复
可以递归组合吧。 with tab as ( select '1' a from dual union all select '1,2' from dual union all select '1,3' from dual union all select '1,2,3' from dual union all select '2' from dual union all select '2,3' from dual union all select '3' from dual ), all_result as ( select rownum id, t1.a aa, t2.a bb, t3.a cc, t4.a dd from tab t1, tab t2, tab t3, tab t4) , data1 as ( select 1 data_id, 1 a, 2 b, 3 c, 3 d from dual union all select 2, 2 a, 2 b, 3 c, 3 d from dual union all select 4, 3 a, 1 b, 1 c, 2 d from dual union all select 3, 2 a, 2 b, 3 c, 3 d from dual ), data2 as ( select distinct * from data1) ,result1 as ( select t1.*, t2.*, count(distinct t2.a) over(partition by t1.id) cta, count(distinct t2.b) over(partition by t1.id) ctb, count(distinct t2.c) over(partition by t1.id) ctc, count(distinct t2.d) over(partition by t1.id) ctd, count( t2.a) over(partition by t1.id, t2.a) checkta, count( t2.b) over(partition by t1.id, t2.b) checktb, count( t2.c) over(partition by t1.id, t2.c) checktc, count( t2.d) over(partition by t1.id, t2.d) checktd, (length(t1.aa) + 1) / 2 la, (length(t1.bb) + 1) / 2 lb, (length(t1.cc) + 1) / 2 lc, (length(t1.dd) + 1) / 2 ld from all_result t1, data2 t2 where 1 = 1 and instr(t1.aa, t2.a) > 0 and instr(t1.bb, t2.b) > 0 and instr(t1.cc, t2.c) > 0 and instr(t1.dd, t2.d) > 0 ) ,result2 as ( select * from result1 t1 where 1 = 1 and cta = la and ctb = lb and ctc = lc and ctd = ld and t1.id not in ( select id from result1 v1 where v1.checkta + v1.checktb + v1.checktc + v1.checktd = 4 ) ) ,fin1 as ( select t1.*, count(1) over(partition by t1.id) all_id_max from result2 t1, data2 t2 where 1 = 1 and instr(t1.aa, t2.a) > 0 and instr(t1.bb, t2.b) > 0 and instr(t1.cc, t2.c) > 0 and instr(t1.dd, t2.d) > 0 ), fin2 as ( select t1.*, max(t1.all_id_max) over(partition by t1.data_id) data_max_all_id from fin1 t1 ), clu_fin as ( select distinct t1.id, aa, bb, cc, dd from fin2 t1 where t1.all_id_max = t1.data_max_all_id ) select to_char(t1.data_id) q, to_char(t1.a) w, to_char(t1.b) e, to_char(t1.c) r, to_char(t1.d) t from data2 t1 where t1.data_id not in ( select t2.data_id from clu_fin t1, data2 t2 where 1 = 1 and instr(t1.aa, t2.a) > 0 and instr(t1.bb, t2.b) > 0 and instr(t1.cc, t2.c) > 0 and instr(t1.dd, t2.d) > 0) union all select to_char(t2.id), to_char(t2.aa), to_char(t2.bb), to_char(t2.cc), to_char(t2.dd) from clu_fin t2 ;
ifvlr 2018-05-09
  • 打赏
  • 举报
回复
另外,还有一个拆分排列组合需求,如

拆分成

同样还是 出现组合的数据可能出现在任何字段。 可能有一个字段是组合的,也可能是多个字段组合的。请问有什么号办法呢?






引用 1 楼 wmxcn2000 的回复:
楼主研究下 listagg 这个函数,真好适合你现在的需求。

大概如下

select a,b,c,
litangg(d,',') within group(order by d)
from t
group by a,b,c


-- 注意:拼接后的长度,不能超过4000。



引用 2 楼 baidu_36457652 的回复:
这个合并用 listagg可以达到,但是你这排列组合方式的方式达到你的效果估计难了
ifvlr 2018-05-02
  • 打赏
  • 举报
回复
引用 2 楼 baidu_36457652 的回复:
这个合并用 listagg可以达到,但是你这排列组合方式的方式达到你的效果估计难了
是的,可能需要多层嵌套,按照一楼的解法,每次组合一个字段,把这个结果继续拿去做嵌套查询,有多少列就嵌套多少次,那样可能能得到一个合并后的结果,但并不一定是最优结果。
ifvlr 2018-05-02
  • 打赏
  • 举报
回复
引用 1 楼 wmxcn2000 的回复:
楼主研究下 listagg 这个函数,真好适合你现在的需求。 大概如下 select a,b,c, litangg(d,',') within group(order by d) from t group by a,b,c -- 注意:拼接后的长度,不能超过4000。
您说的这种方式只考虑了一个字段,而我的需求不只是D列这一个字段需要组合,而是A,B,C列均有存在组合的可能,如t_sort_and_comb_result表中的第三条记录,第三条记录就是由4条记录合并而来的。。当然实际的数据,是有十几个列,几千行数据的合并,每一个列都可能存在一个or多个组合,把能合并的数据合并,不能合并的数据保持原样。得到的结果条数最少为最优解。 您说的这种方式和我写group by 然后用wm_concat方式合并感觉差不多哦~ 我在网上找了下,感觉listagg并不能直接解决我的问题。 另外 litangg--> listagg
卖水果的net 2018-04-30
  • 打赏
  • 举报
回复
楼主研究下 listagg 这个函数,真好适合你现在的需求。 大概如下 select a,b,c, litangg(d,',') within group(order by d) from t group by a,b,c -- 注意:拼接后的长度,不能超过4000。
  • 打赏
  • 举报
回复
这个合并用 listagg可以达到,但是你这排列组合方式的方式达到你的效果估计难了

3,494

社区成员

发帖
与我相关
我的任务
社区描述
Oracle 高级技术相关讨论专区
社区管理员
  • 高级技术社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧