oracle质数怎么算,借花献佛之使用Oracle sql求质数(笔记)

首先声明一点,文章内容从itpub论坛上看到的,原文链接 http://www.itpub.net/thread-1849398-1-1.html

,本文主要是记录下笔记,原文中有更详细的分析。使用sql求质素没什么实用价值,重要的是思路。

(一)最简单的方法

思路:将2和所有大于等于3小于XX的奇数取出来,做一中间结果集t。然后逐一校验t中的每个N是否是质数。如果发现一个数字N不能被其他所有数字整除——当然,这些数字要小于等于SQRT(N),那么N就是质数

with t as(select 2 n from dual union select rownum*2+1 from dual connect by rownum<=(10000-2)/2)

select count(*) from t a where not exists (select null from t b where b.n<=sqrt(a.n) and mod(a.n, b.n)=0)

最直接的方法,可惜速度最慢。

(二)筛选法

思路:将从2到XX的数都列出来,作为一个全集,然后减去所有的合数,即可得到素数集合

WITH t AS (

SELECT ROWNUM+1 rn FROM DUAL CONNECT BY ROWNUM <= 10000-1)

SELECT COUNT(*)

FROM (SELECT rn

from t

MINUS

SELECT t1.rn * t2.rn--4=2*2 2*3 9=3*3 3*4 16=4*4 4*5

FROM t t1, t t2

WHERE t1.rn <= t2.rn

AND t1.rn <= (SELECT SQRT(10000) FROM DUAL))

(三)改进的筛选法

思路:除了2之外的偶数,可以从全集和合数集中排除

WITH t AS (

--2-10000/2

SELECT ROWNUM+1 rn FROM DUAL CONNECT BY ROWNUM <= 10000/2-1

)

,t_odd AS (

--奇数

SELECT 2*ROWNUM+1 rn FROM DUAL CONNECT BY ROWNUM <= 10000/2-1

)

SELECT COUNT(*) + 1--+2

FROM (SELECT rn

from t_odd

MINUS

SELECT t1.rn * t2.rn

FROM t t1, t t2

WHERE t1.rn <= t2.rn

AND t1.rn <= (SELECT SQRT(10000) FROM DUAL)

AND t1.rn * t2.rn < 10000)

另一种写法:排除偶数

WITH t_odd AS (

SELECT 2*ROWNUM+1 rn FROM DUAL CONNECT BY ROWNUM <= 10000/2-1

)

SELECT COUNT(*) + 1

FROM (SELECT rn

from t_odd

MINUS

SELECT t1.rn * t2.rn --9=3*3 3*5 25=5*5 5*7 49=7*7

FROM t_odd t1, t_odd t2

WHERE t1.rn <= t2.rn

AND t1.rn <= (SELECT SQRT(10000) FROM DUAL)

AND t1.rn * t2.rn < 10000)

(四)逆向exists

with t as(select 2 n from dual union select rownum*2+1 from dual connect by rownum<=(10000-2)/2)

, z as (select * from t minus

select * from t a where exists (select null from t b where b.n<=sqrt(a.n) and mod(a.n, b.n)=0))

select count(*) from z

或者:

with t as(select rownum*2+1 n from dual connect by rownum<=(10000-2)/2

union select 3 from dual --F5执行计划 走MERGE JOIN

),z as (select * from t minus

select * from t a where exists (select null from t b where b.n<=sqrt(a.n) and mod(a.n, b.n)=0))

select count(*)+1 from z

加了union select 3 from dual 之后,执行计划走MERGE JOIN,这一点还没想明白,欢迎指教。

(五)提前剔除奇数

WITH t0 AS (

SELECT 2*ROWNUM+1 rn FROM DUAL CONNECT BY ROWNUM <= (10000)/2-1

),

t as(SELECT rn from t0 where mod(rn,3)<>0 and 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)

SELECT COUNT(*) + 1 + 7 --2,3,5,7,11,13,17,19

FROM (SELECT rn

from t

MINUS

SELECT t1.rn * t2.rn

FROM t t1, t t2

WHERE t1.rn <= t2.rn

AND t1.rn BETWEEN 9 AND (SELECT SQRT(10000) FROM DUAL)

AND t1.rn * t2.rn < 10000)

其实后面的大部分写法都是采用提前筛选掉不合格的数字来减少源数据大小达到加快查询速度。

全文完。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值