|
用OO的素数表写SQL:
var n number;
exec :n:=1000000
with ta as
(select level*2+1 l from dual connect by level<=sqrt(:N)/2),
t1 as (select level*2+1 l from dual connect by level<=sqrt(:N)/3)
,p1k as(select l rn from ta --1000以内的质数
minus
select t1.l*t2.l from t1,t1 t2 where t1.l<=sqrt(sqrt(:N))
and t1.l<=t2.l and t1.l*t2.l<=:N
)
,t0 AS (
SELECT 6*ROWNUM+1 rn FROM DUAL CONNECT BY ROWNUM <= (:n)/6
union all
SELECT 6*ROWNUM+5 rn FROM DUAL CONNECT BY ROWNUM <= (:n)/6
)
,t as(SELECT rn from t0
where mod(rn,5)<>0
and mod(rn,7)<>0
and mod(rn,11)<>0
and mod(rn,13)<>0
and mod(rn,17)<>0
and mod(rn,19)<>0
and mod(rn,23)<>0
and mod(rn,29)<>0
and rn<:n
)
,tnew as(SELECT rn from t
MINUS
SELECT /*+ USE_MERGE (t1 t2) */ t1.rn * t2.rn
FROM p1k t1, t t2
WHERE t1.rn <= t2.rn
AND t1.rn BETWEEN 31 AND (SELECT SQRT(:n) FROM DUAL)
AND t1.rn * t2.rn <:n and t2.rn<=:n/31
union select * from p1k where rn<31
union select 2 from dual
)
SELECT n2,MIN(rn),COUNT(*)
FROM (
SELECT rn
,SYS_CONNECT_BY_PATH(DECODE(n,1,'*',SUBSTR(rn,LEVEL,1)),',') n2
,SYS_CONNECT_BY_PATH(DECODE(n,1,SUBSTR(rn,LEVEL,1)),',') n3
FROM tnew,(SELECT 0 n FROM DUAL UNION ALL SELECT 1 FROM DUAL)
WHERE LEVEL=LENGTH(rn)
CONNECT BY NOCYCLE rn=PRIOR rn AND LEVEL<=LENGTH(rn) AND PRIOR DBMS_RANDOM.VALUE IS NOT NULL
)
WHERE LENGTH(TRANSLATE('0123456789',n3,','))=9
GROUP BY n2
HAVING COUNT(*)>=8;
N2
-------------------------------
MIN(RN) COUNT(*)
---------- ----------
,*,2,*,3,*,3
121313 8
Elapsed: 00:03:14.21
竟然花了三分多钟,可能因为CONNECT BY里面用到了DBMS_RANDOM. 改用递归WITH:
with ta as
(select level*2+1 l from dual connect by level<=sqrt(:N)/2),
t1 as (select level*2+1 l from dual connect by level<=sqrt(:N)/3)
,p1k as(select l rn from ta --1000以内的质数
minus
select t1.l*t2.l from t1,t1 t2 where t1.l<=sqrt(sqrt(:N))
and t1.l<=t2.l and t1.l*t2.l<=:N
)
,t0 AS (
SELECT 6*ROWNUM+1 rn FROM DUAL CONNECT BY ROWNUM <= (:n)/6
union all
SELECT 6*ROWNUM+5 rn FROM DUAL CONNECT BY ROWNUM <= (:n)/6
)
,t as(SELECT rn from t0
where mod(rn,5)<>0
and mod(rn,7)<>0
and mod(rn,11)<>0
and mod(rn,13)<>0
and mod(rn,17)<>0
and mod(rn,19)<>0
and mod(rn,23)<>0
and mod(rn,29)<>0
and rn<:n
)
,tnew as(SELECT rn from t
MINUS
SELECT /*+ USE_MERGE (t1 t2) */ t1.rn * t2.rn
FROM p1k t1, t t2
WHERE t1.rn <= t2.rn
AND t1.rn BETWEEN 31 AND (SELECT SQRT(:n) FROM DUAL)
AND t1.rn * t2.rn <:n and t2.rn<=:n/31
union select * from p1k where rn<31
union select 2 from dual
)
,w(rn,n2,n3,lvl) AS (
SELECT rn,CAST(DECODE(n,1,'*',SUBSTR(rn,1,1)) AS VARCHAR2(10)),CAST(DECODE(n,1,SUBSTR(rn,1,1)) AS VARCHAR2(1)),1
FROM tnew,(SELECT 0 n FROM DUAL UNION ALL SELECT 1 FROM DUAL)
UNION ALL
SELECT rn,n2||DECODE(n,1,'*',SUBSTR(rn,lvl+1,1)),NVL(n3,DECODE(n,1,SUBSTR(rn,lvl+1,1))),lvl+1
FROM w,(SELECT 0 n FROM DUAL UNION ALL SELECT 1 FROM DUAL)
WHERE lvl<LENGTH(rn) AND (n3 IS NULL OR n=0 OR n=1 AND SUBSTR(rn,lvl+1,1)=n3)
)
SELECT n2,MIN(rn),COUNT(*)
FROM w
WHERE lvl=LENGTH(rn)
GROUP BY n2
HAVING COUNT(*)>=8;
N2 MIN(RN) COUNT(*)
------------------ ---------- ----------
*2*3*3 121313 8
Elapsed: 00:01:09.24 |
|