简体   繁体   English

如何打印给定范围内的素数 | Oracle 19c |

[英]How to print prime numbers within given range | Oracle 19c |

I have been trying to write a logic to print all prime numbers .我一直在尝试编写一个逻辑打印所有素数

And it works as expected till range of 1 to 100 .它可以按预期工作,直到范围为1100

But when I increase the range it dose not work from 1 to 500但是当我增加范围时,它从1500不起作用

Can some explain in details what is wrong in my below code and how it can be improved.有人可以详细解释我下面的代码有什么问题以及如何改进它。

Any easy or different way to print prime numbers will be much appreciated任何简单或不同的打印素数的方法都将不胜感激

Code:代码:

SELECT
    result
FROM
    (
        SELECT
            CASE
                WHEN ROWNUM = 2 THEN
                    ROWNUM
                WHEN ROWNUM = 3 THEN
                    ROWNUM
                WHEN ROWNUM = 5 THEN
                    ROWNUM
            END AS result
        FROM
            dual
        CONNECT BY
            ROWNUM <= 5
    )
WHERE
    result IS NOT NULL
UNION ALL
SELECT
    result
FROM
    (
        SELECT
            decr1 AS result
        FROM
            (
                SELECT
                    rn AS decr1
                FROM
                    (
                        SELECT
                            ROWNUM AS rn
                        FROM
                            dual
                        CONNECT BY
                            ROWNUM < 1000
                    )
            )
        WHERE
            decr1 > 5
        MINUS
        SELECT
            decr AS result
        FROM
            (
                SELECT
                    t.rn AS decr
                FROM
                    (
                        SELECT
                            ROWNUM AS rn
                        FROM
                            dual
                        CONNECT BY
                            ROWNUM < 1000
                    ) t
                WHERE
                    rn >= 6
            )
        WHERE
            mod(decr, 2) = 0
            OR mod(decr, 3) = 0
            OR mod(decr, 4) = 0
            OR mod(decr, 5) = 0
            OR mod(decr, 6) = 0
            OR mod(decr, 7) = 0
            OR mod(decr, 8) = 0
            OR mod(decr, 9) = 0
            OR mod(decr, 10) = 0
    );

My output for range of 1 to 100我的 output 范围为1100

输出

A positive integer is prime if it is strictly greater than 1, and if it is not divisible by any positive integers besides 1 and the number itself.正数 integer 如果严格大于 1,并且不能被除 1 和数字本身之外的任何正整数整除,则它是素数。 To check for primality, it is enough to know if the number is divisible by a number between 2 and trunc(sqrt(that_number)).要检查素数,知道该数字是否可以被 2 和 trunc(sqrt(that_number)) 之间的数字整除就足够了。 In code:在代码中:

with
  user_input (n) as (
    select :n              -- user input goes here
    from   dual
  )
, candidates (p) as (
    select  level
    from    user_input 
    where   level > 1
    connect by level <= n
  )
, prep (f) as (
    select  level
    from    dual
    where   level > 1
    connect by level <= trunc(sqrt(:n))
  )
select p as prime
from   candidates
where  not exists (
                    select f
                    from   prep
                    where  f <= trunc(sqrt(p))
                           and
                           mod(p, f) = 0
                  )
;

The input (at the top of the query, in the with clause) is a bind variable, you can set it to 100 or whatever you need.输入(在查询的顶部,在with子句中)是一个绑定变量,您可以将其设置为 100 或任何您需要的值。

NOTE: This will be quite slow if you need all the primes up to 100,000 for example (it takes 2.3 seconds on my machine).注意:例如,如果您需要所有素数高达 100,000,这将非常慢(在我的机器上需要 2.3 秒)。 Don't even try up to 1 million or more.甚至不要尝试达到 100 万或更多。 For those, you need a better algorithm.对于那些,你需要一个更好的算法。 We all learned the Erathostenes' sieve algorithm in primary school;我们在小学都学过 Erathostenes 的筛分算法; that is trivial to code in a procedural language (like PL/SQL), not so easy in a declarative language (like SQL - proving that "declarative" is just a marketing word, and perhaps an ideal, but not a reality).这对于用过程语言(如 PL/SQL)编写代码来说是微不足道的,但在声明性语言(如 SQL - 证明“声明性”只是一个营销词,也许是一个理想,但不是现实)中并不容易。 For a pretty long discussion see https://community.oracle.com/tech/developers/discussion/3931268/sql-puzzle-prime-numbers/p1 which was rendered hard to read by Oracle's change of forum platform provider a few years back.对于相当长的讨论,请参阅https://community.oracle.com/tech/developers/discussion/3931268/sql-puzzle-prime-numbers/p1几年前 Oracle 更改论坛平台提供商时很难阅读.

select num prime_number
from (select level num from dual connect by level <= 500 ),
 (select level denom from dual connect by level <= 500 )
where denom<=num
group by num
having count(case num/denom when trunc(num/denom) then 'Y' end) = 2
order by num

Using Oracle's connect, we can generate our set of numerators and denominators.使用 Oracle 的连接,我们可以生成我们的一组分子和分母。 Then we can filter any denominators greater than the numerator (no point in dividing 2 by 3, etc).然后我们可以过滤任何大于分子的分母(没有必要将 2 除以 3 等)。 Finally, the having clause will return the prime numbers.最后,having 子句将返回素数。

Fiddle The first query in the fiddle kind of shows what is going on, the second one is gives you your primes.小提琴 小提琴中的第一个查询显示正在发生的事情,第二个查询是给你你的素数。

You've thrown out processing efficiency when you decided to do this in SQL, so you might as well go for something that is clear.当您决定在 SQL 中执行此操作时,您已经放弃了处理效率,因此您不妨 go 来做一些明确的事情。 Here is a SQL that is pretty much straight along the lines of the definition of a prime number:这是一个 SQL ,它与质数的定义非常相似:

with nat as (SELECT rownum n FROM DUAL CONNECT BY ROWNUM <= 100 )
SELECT n   -- give me any number...
from   nat n1  -- ... from the set of natural numbers ...
where   not exists ( SELECT n FROM nat n2 where mod(n1.n,n2.n)=0 AND n2.n between 2 and n1.n-1)  -- ... that cannot be evenly divided by a smaller natural number
and n > 1  -- ... and 1 is not prime

Adjust the CONNECT by value if you want more or less values如果您想要更多或更少的值,请按值调整 CONNECT


select a output
    from (select level a from dual connect by level <= 500),
         (select level b from dual connect by level <= 500)
    where b<=a
    group by a
    having count(case a/b when trunc(a/b) then 'Y' end) = 2
    order by a;

You can use use a row-generator to generate all the values and then use CROSS JOIN LATERAL to check if each value is prime:您可以使用行生成器生成所有值,然后使用CROSS JOIN LATERAL检查每个值是否为素数:

SELECT prime
FROM   (
         SELECT LEVEL + 1 AS prime
         FROM   DUAL
         CONNECT BY LEVEL < 100
       ) p
       CROSS JOIN LATERAL (
         SELECT 1
         FROM   DUAL
         WHERE  MOD(prime, level) = 0
         CONNECT BY LEVEL * LEVEL <= prime
         HAVING COUNT(*) = 1
       )

Which outputs:哪个输出:

PRIME主要
2 2
3 3
5 5
7 7
11 11
13 13
17 17
19 19
23 23
29 29
31 31
37 37
41 41
43 43
47 47
53 53
59 59
61 61
67 67
71 71
73 73
79 79
83 83
89 89
97 97

fiddle小提琴

Hooray finally !!!终于万岁了!!!

I was able to solve the question by taking references from all @authors我能够通过参考所有@authors 来解决这个问题

My sincere thank you to all the author who as come up with different solution我真诚地感谢所有提出不同解决方案的作者

I got few ideas from your logic which help me to write a below query我从你的逻辑中得到了一些帮助我编写以下查询的想法

My code:我的代码:

with input(val) as
(
        SELECT
            :val
        FROM
            dual
)
,
auto_generate_number_sequence as
(
        SELECT
            numbr
        FROM
            (
                SELECT
                    6 * level - 1 AS numbr
                FROM
                    dual
                CONNECT BY
                    level < :val
                UNION
                SELECT
                    6 * level + 1 AS numbr
                FROM
                    dual 
                CONNECT BY
                    level < :val 
            )
        WHERE
            numbr <= :val
) , 
generate_sqrt_of_input as 
(
            select 
                level as sqrtnum 
                   from dual where  level > 1 connect by level <=sqrt(:val)  
)
, get_numbers_remainder_zero as 
(
        SELECT
            numbr,
            mod(numbr, sqrtnum) AS md
        FROM
                 auto_generate_number_sequence
            CROSS JOIN generate_sqrt_of_input
        WHERE
                sqrtnum < (numbr/2)
            AND mod(numbr, sqrtnum) = 0
        ORDER BY
            numbr,
            mod(numbr, sqrtnum)
)
SELECT
            level numbr
        FROM
            dual where level > 1 
        CONNECT BY
            level <=3
UNION
SELECT
    numbr
FROM
    auto_generate_number_sequence
MINUS
SELECT
    numbr
FROM
    get_numbers_remainder_zero;

Please feel free to correct me If any issue with my above query如果我的上述查询有任何问题,请随时纠正我

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM