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

时间:2015-02-18 16:04:00

标签: sql oracle plsql

这是我的代码

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;

我收到错误:

  

从第2行开始出错:命令中的错误 - 错误报告 - ORA-06550:行   18,第4栏:PLS-00103:遇到符号&#34 ;;"当期待一个   以下内容:

     

如果   06550. 00000 - "行%s,列%s:\ n%s"   *原因:通常是PL / SQL编译错误。   *行动:       END;

3 个答案:

答案 0 :(得分:4)

此IF没有END IF - IF IS_PRIME = 1 THEN

完整的END;阻止没有BEGIN...END

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

  

行动:结束;

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

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

  1. 检查素数时,您不必循环直到num-1。循环直到平方根(num)将正常工作。 Proof

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

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

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

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

    3. 这是正确的程序 -

      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;
      /
      

答案 1 :(得分:3)

你没有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)。

答案 2 :(得分:1)

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以下的所有素数。由于在一秒钟内产生完整的结果,额外的工作是无关紧要的。