最近看到一个这样的面试题:
实现一个函数(使用 Java),输入一个数组,例如 1121121123115; 找到所有符合 A+B=C 模式的连续的值;例如 1+1=2; 112+3=115;
要求最终结果如下:
撇开 Java 和 PL/SQL 不看,毕竟也就是一个三重或者四重循环的事情,笔者手痒,希望能从 SQL 端入手,解决这个问题。
注:下文中测试用字符串为:112112112113224225123
笔者的 SQL 如下:
With tmp01 as(select '112112112113224225123' str from dual),
Tmp02 as(
Select str,level rn from tmp01 t1 connect by level<=length (str))
Select substr('112112112113224225123',t1.rn,t2.rn)||'+'||
substr('112112112113224225123',t1.rn+t2.rn,t3.rn)||'='||
substr('112112112113224225123',t1.rn+t2.rn+t3.rn,t4.rn) "a+b=c"
from tmp02 t1,tmp02 t2,tmp02 t3,tmp02 t4
where substr('112112112113224225123',t1.rn,t2.rn)+
substr('112112112113224225123',t1.rn+t2.rn,t3.rn)=
substr('112112112113224225123',t1.rn+t2.rn+t3.rn,t4.rn)
and t1.rn+t2.rn+t3.rn+t4.rn<=length('112112112113224225123')+1;
思想是:借用字符串的长度,生成一个 1~length(str) 的结果集,然后利用这个结果集进行自连接,暴力破解出所有的组合可能性,满足 where 条件,也就是 A+B=C 这种情况的,我们筛选出来,这就是最终的结果。where 条件中的 t1.rn+t2.rn+t3.rn+t4.rn 是为了屏蔽 substr 函数中,截取长度不够的问题。
从分析和运行结果来看,功能是 ok 的,但是性能上似乎有点问题。当然,用 SQL 去解一些本应该程序做的事情,性能大多数时候都不会好到哪去。但是,在有限范围内,总会有人去无限优化,去接近极限值。下面就是 newkid 大叔的写法,他避免了第三次截取,只要结果集保证前两次截取剩下的字符串,正好可以满足前两次连续截取的字符串值的和的后缀 % 匹配,如第一次截取 1,第二次截取 2,剩下值是 3**********就满足了条件。
–newkid 进阶写法
注:在 DM 管理工具中执行时,请修改配置文件 COMPATIBLE_MODE=2。
with tmp01 as(select ‘112112112113224225123’ str from dual),
tmp02 as(
select level rn from tmp01 t1 connect by level<=length(str))
select substr(‘112112112113224225123’,t1.rn,t2.rn)||’+’||
substr(‘112112112113224225123’,t1.rn+t2.rn,t3.rn)||’=’||
(substr(‘112112112113224225123’,t1.rn,t2.rn)+
Substr(‘112112112113224225123’,t1.rn+t2.rn,t3.rn)) “a+b=c”
from tmp02 t1,tmp02 t2,tmp02 t3--,tmp02 t4
where substr(‘112112112113224225123’,t1.rn+t2.rn+t3.rn) like
(substr(‘112112112113224225123’,t1.rn,t2.rn)+
Substr(‘112112112113224225123’,t1.rn+t2.rn,t3.rn))||’&’;
注:以上 SQL 在 DM7.1.5.121版运行通过。
经过测试,后面的写法,性能提升 10~15 倍。
结论:建索引、看计划、考虑扫描方式是优化的常规方法,但是并非适用于所有场合,偶尔换个思路,跳出局限,或许效果会更好。
文章
阅读量
获赞