|
原帖由 〇〇 于 2010-12-12 13:43 发表 ![]()
newkid的gcd
SQL> WITH n AS (
2 select level*10 n from dual connect by level
我的写法每一步都会和集合n做连接,如果n很大, 效率就成问题。NB哥的好一些因为他只是在b2=0才会执行一个子查询。
如果集合是很有规律的,那么只要在递归的每一步生成新数据就行了,集合n没有必要:
WITH t (id,a,b,gcd) AS (
SELECT 10,0,1,10 FROM DUAL
UNION ALL
SELECT DECODE(t.a,0,t.id+10,t.id)
,DECODE(t.a,0,t.id+10,MOD(t.b,t.a))
,DECODE(t.a,0,t.gcd,t.a)
,DECODE(mod(t.b,t.a),0,t.a,t.gcd)
FROM t
WHERE (t.id<1E5 OR t.id=1E5 AND t.a<>0)
)
SELECT gcd FROM t WHERE a=0 AND id=1E5;
GCD
----------
10
Elapsed: 00:00:00.45
如果集合n不能省略,最好的办法就是把它变成hash表放在内存里直接访问,可惜ORACLE的递归WITH没有这高级功能。
改用MODEL, 引用效率高了,但是没办法精确控制迭代次数,不得不先构造一个笛卡尔积。
SELECT b
FROM (SELECT *
FROM (SELECT ROWNUM n
,ROWNUM*10 val ---- 用另外的列存放要求公倍数的值。不一定是连续的自然数
FROM DUAL
CONNECT BY ROWNUM<=1e4)
,(SELECT ROWNUM col
FROM DUAL
CONNECT BY ROWNUM<=30 ---- 假设辗转相除法迭代次数不超过30
)
MODEL IGNORE NAV RETURN UPDATED ROWS
DIMENSION BY (n,col)
MEASURES (val,0 a,val b)
RULES AUTOMATIC ORDER (
a[n>1,any] order by n,col = CASE WHEN cv(col)=1 THEN val[cv(),cv()]
WHEN a[cv(),cv()-1]<>0 THEN MOD(b[cv(),cv()-1],a[cv(),cv()-1])
ELSE 0
END
,b[n>1,any] order by n,col = CASE WHEN cv(col)=1 THEN b[cv()-1,30]
WHEN a[cv(),cv()-1]<>0 THEN a[cv(),cv()-1]
ELSE b[cv(),cv()-1]
END
)
)
WHERE n=1E4 and col=30;
B
----------
10
Elapsed: 00:00:11.73 |
|