如何在 Oracle SQL 中获取 1000-2000 之间的素数

How to get prime numbers between 1000-2000 in Oracle SQL

这是我的代码

SET SERVEROUTPUT ON;
DECLARE
ACOUNTER INTEGER;
IS_PRIME INTEGER;
BEGIN
IS_PRIME := 1;
FOR NUM IN 1000..2000 LOOP
    FOR D IN 2..NUM-1 LOOP
        IF MOD(NUM,D) = 0 THEN
        IS_PRIME := 0;
        END IF;
      END LOOP; 
END LOOP;

IF IS_PRIME = 1 THEN
ACOUNTER := ACOUNTER +1;

DBMS_OUTPUT.PUT_LINE('THE # OF PRIME NUMBERS BETWEEN 1000-2000 ARE: ' || ACOUNTER);
END;

我收到一个错误:

Error starting at line : 2 in command - Error report - ORA-06550: line 18, column 4: PLS-00103: Encountered the symbol ";" when expecting one of the following:

if 06550. 00000 - "line %s, column %s:\n%s" *Cause: Usually a PL/SQL compilation error. *Action: END;

您没有END IF;给定报告错误的行号,您在显示的内容之后有一个 END;,所以最后几行是:

...
IF IS_PRIME = 1 THEN
ACOUNTER := ACOUNTER +1;

DBMS_OUTPUT.PUT_LINE('THE # OF PRIME NUMBERS BETWEEN 1000-2000 ARE: ' || ACOUNTER);
END;
/

当编译器看到 END; 时,它期望前面的 IF 被关闭,所以当它看到 ; 时抛出异常。只需在素数检查后添加一个 END IF

...
    IF IS_PRIME = 1 THEN
        ACOUNTER := ACOUNTER +1;
    END IF;

    DBMS_OUTPUT.PUT_LINE('THE # OF PRIME NUMBERS BETWEEN 1000-2000 ARE: ' || ACOUNTER);
END;
/

一致的缩进使这种更明显,更容易追踪。

您还在错误的位置设置和检查您的标志 - 两者都应该在第一个循环内 - 并且您必须在开始之前初始化您的计数器,因为它将默认为 null:

DECLARE
    ACOUNTER INTEGER := 0;
    IS_PRIME INTEGER;
BEGIN
    FOR NUM IN 1000..2000 LOOP
        IS_PRIME := 1;
        FOR D IN 2..NUM-1 LOOP
            IF MOD(NUM,D) = 0 THEN
                IS_PRIME := 0;
            END IF;
        END LOOP; 

        IF IS_PRIME = 1 THEN
            ACOUNTER := ACOUNTER +1;
        END IF;
    END LOOP;

    DBMS_OUTPUT.PUT_LINE('THE # OF PRIME NUMBERS BETWEEN 1000-2000 ARE: ' || ACOUNTER);
END;
/

anonymous block completed
THE # OF PRIME NUMBERS BETWEEN 1000-2000 ARE: 135

也请参阅@ruudvan 关于您的算法的评论;该版本得到相同的答案 135,但效率更高(在我的系统上用十分之一的时间;大约 0.06 秒,而使用这种更简单的方法则为 0.60 秒)。

这个IF没有END IF - IF IS_PRIME = 1 THEN

完整的 BEGIN...END 块没有 END;

错误告诉你必须采取什么行动 -

Action: END;

这通常意味着您必须将 END 关键字放在某处。

关于寻找素数算法的一些建议 -

  1. 检查质数时,不必循环到 num-1。循环直到 square-root(num) 将正常工作。 Proof

  2. 当你找到一个不是素数的数字时,退出循环。无需检查该数字的任何进一步除数。

编辑:你的逻辑错误会给你不正确的结果 -

  1. 在第一个循环中,将变量IS_PRIME重新初始化为1。

  2. 计数器递增应该发生在第一个循环内。

这是正确的程序 -

SET SERVEROUTPUT ON;

DECLARE
   ACOUNTER   INTEGER;
   IS_PRIME   INTEGER;
BEGIN
   ACOUNTER   := 0;
   IS_PRIME   := 1;

   FOR NUM IN 1000 .. 2000
   LOOP
      IS_PRIME   := 1;

      FOR D IN 2 .. SQRT (num)
      LOOP
         IF MOD (NUM, D) = 0
         THEN
            IS_PRIME   := 0;
            EXIT;
         END IF;
      END LOOP;

      IF IS_PRIME = 1
      THEN
         ACOUNTER   := ACOUNTER + 1;
      END IF;
   END LOOP;

   DBMS_OUTPUT.PUT_LINE (
      'THE # OF PRIME NUMBERS BETWEEN 1000-2000 ARE: ' || ACOUNTER);
END;
/

Alex Poole 已经解决了您代码中的实际问题。然而,与许多问题一样,如果您要在数据库中解决这个问题,您可能最好使用 SQL。本着这种精神,SQL 解决了这个问题。

WITH pc AS
        (SELECT *
         FROM   (SELECT     LEVEL AS numbers
                 FROM       DUAL
                 CONNECT BY LEVEL <= 2000)
         WHERE  (numbers = 2 OR MOD (numbers, 2) <> 0) AND numbers <> 1)
SELECT *
FROM   (SELECT numbers FROM pc
        MINUS
        SELECT pc1.numbers
        FROM   pc pc1
               JOIN pc pc2
                  ON     pc2.numbers <= CEIL (SQRT (pc1.numbers))
                     AND MOD (pc1.numbers, pc2.numbers) = 0)
WHERE  numbers BETWEEN 1000 AND 2000

connect by 生成 1 到 2000 之间的所有数字。使用广为接受的规则,我们可以消除所有大于 2 的偶数,并且只测试每个数字的模数以获取小于该数字平方根的值。

从技术上讲,此解决方案生成 2 到 2000 之间的每个素数,然后过滤掉 2000 以下的所有素数。由于在不到一秒的时间内生成完整结果,因此额外的工作无关紧要。

如果可能的话,

Always 是一个更好的选择,只使用 SQL 而不是 PLSQL

WITH A AS (
 SELECT LEVEL AS L FROM DUAL CONNECT BY LEVEL <= 2000
)
SELECT 
LISTAGG(L,', ') WITHIN GROUP (ORDER BY L)
FROM 
    (
        SELECT L FROM A MAIN
        WHERE L >= 1000 AND
        NOT EXISTS
        (
            SELECT 1 FROM A SUB
            WHERE 
            MAIN.L>SUB.L
            AND MOD(MAIN.L,L)=0
            AND SUB.L>1
        )
        AND L<>1
    );