遇到一道有意思的题目,使用sql找到100以内的质数
SELECT
n1.num
FROM
Numbers2 AS n1
WHERE
NOT EXISTS(
SELECT
*
FROM
Numbers2 AS n2
WHERE
n2.num > 1
AND n1.num > n2.num
AND n1.num % n2.num = 0
)
AND n1.num > 1
GROUP BY
n1.num
ORDER BY
n1.num;
质数是除了1和它本身,不存在正约数的,大于1的自然数。
大概小学数学的概念,当然,关于它的研究是相当难的。
第一步是构造一个从1到100的数据表,如果生写,比较麻烦,可以用0到9的表搞一个笛卡尔积:
SELECT
num
FROM
Numbers
ORDER BY
num;
/*
num
-----
0
1
2
3
4
5
6
7
8
9
(10 rows)
*/
INSERT INTO
Numbers2 (num)
SELECT
(n1.num + n2.num * 10) AS num
FROM
Numbers n1,
Numbers n2
ORDER BY
num;
接着要构造查询语句,思考几个条件:
- 质数要大于1。
- 在1和其本身之间,没有约数,更进一步,在1和其本身的一半之间,没有约数。
用sql的方法筛选,就需要构造一个这样的表
SELECT
n1.num AS n1_num,
n2.num AS n2_num,
n1.num % n2.num AS n1_n2_mod
FROM
Numbers2 AS n1,
Numbers2 AS n2
WHERE
n2.num > 1
AND n1.num > n2.num
ORDER BY
n1.num;
-- n1_num | n2_num | n1_n2_mod
----------+--------+-----------
-- 3 | 2 | 1
-- 4 | 2 | 0
-- 4 | 3 | 1
-- 5 | 2 | 1
-- 5 | 3 | 2
-- 5 | 4 | 1
-- 6 | 2 | 0
-- 6 | 3 | 0
-- 6 | 4 | 2
-- 6 | 5 | 1
-- 7 | 2 | 1
-- 7 | 3 | 1
-- 7 | 4 | 3
-- 7 | 5 | 2
-- 7 | 6 | 1
然后对n1_num进行GROUP,将表分成若干个集合,只要集合中含余数(n1_n2_mod)为0,则此项n1_num排除。
为了兼顾效率,使用了not exists谓词,其语义是一旦包含约数,立即排除。剩下的就是不包含任何大于1 的正约数的数,也就是质数。
-- num
-------
-- 2
-- 3
-- 5
-- 7
-- 11
-- 13
-- 17
-- 19
-- 23
-- 29
-- 31
-- 37
-- 41
-- 43
-- 47
-- 53
-- 59
-- 61
-- 67
-- 71
-- 73
-- 79
-- 83
-- 89
-- 97
--(25 rows)
参考文献:《SQL进阶教程》作者:[日]MICK 译者:吴炎昌 人民邮电出版社 出版时间:2017-11 / 1-8 EXISTS 谓词用法