编译存储过程时出错

时间:2019-02-22 17:21:41

标签: oracle plsql

我正在编写下面的存储过程,但是在oracle中编译过程时也遇到了异常,下面是过程

CREATE OR REPLACE PACKAGE BODY TEST_TABLE AS 
PROCEDURE TEST_TABLE         


--This procedure will delete partitions for the following tables:
--TEST_TABLE
BEGIN
  FOR cc IN
  (
  SELECT partition_name, high_value
  FROM user_tab_partitions
  WHERE table_name = 'TEST_TABLE'
  )

LOOP
    EXECUTE IMMEDIATE 'BEGIN               
IF sysdate >= ADD_MONTHS(' || cc.high_value || ', 3) THEN                  
EXECUTE IMMEDIATE                     
''ALTER TABLE TEST_TABLE DROP PARTITION ' || cc.partition_name || '                     
'';               
END IF;    
  dbms_output.put_line('drop partition completed');        
END;';
  END LOOP;

  exception
                when others then
                                dbms_output.put_line(SQLERRM);

END;

END; 
/

我在编译时遇到的一个例外是,请提出如何克服这一点的建议。

Error(7,1): PLS-00103: Encountered the symbol "BEGIN" when expecting one of the following:     ( ; is with authid as cluster order using external    deterministic parallel_enable pipelined result_cache The symbol ";" was substituted for "BEGIN" to continue. 

Error(22,25): PLS-00103: Encountered the symbol "DROP" when expecting one of the following:     * & = - + ; < / > at in is mod remainder not rem return    returning <an exponent (**)> <> or != or ~= >= <= <> and or    like like2 like4 likec between into using || bulk member    submultiset  

2 个答案:

答案 0 :(得分:2)

第一条错误消息告诉您BEGIN之前缺少某些内容,甚至还提到了“何时”列表中的两个可能选项。您需要将其更改为:

PROCEDURE TEST_TABLE IS
--                   ^^

或者,如果您愿意...,也可以使用AS代替IS

第二个错误是因为您在动态SQL中嵌入了字符串文字,尽管在其他地方也没有转义单引号:

...
  dbms_output.put_line(''drop partition completed'');
--                     ^                         ^
END;';

您可以改用alternative quoting mechanism

我不确定为什么要执行两个级别的动态SQL。您可以执行dbms_output()并静态评估cc.high_value,并决定是否仅使该部分为动态(如@BarbarosÖzhan所示,因此不重复!),以使alter call。或在游标查询中进行高价值检查。

  

我仍然收到异常错误(1,14):PLS-00304:如果没有说明,就无法编译“ TEST_TABLE”的正文

如果要使用包,则必须先创建其规格,然后再尝试创建其主体:

CREATE OR REPLACE PACKAGE TEST_TABLE AS 
PROCEDURE TEST_TABLE;
END TEST_TABLE;
/

CREATE OR REPLACE PACKAGE BODY TEST_TABLE AS 
PROCEDURE TEST_TABLE IS
BEGIN
  FOR cc IN
  ...
  LOOP
    ...
  END LOOP;
END TEST_TABLE; -- end of procedure
END TEST_TABLE; -- end of package
/

包名称与其中的过程相同,有点奇怪和混乱。

但是也许您实际上根本不需要包,而是试图创建一个独立的过程,在这种情况下,只需删除package-body部分:

CREATE OR REPLACE PROCEDURE TEST_TABLE AS
BEGIN
  FOR cc IN
  ...
  LOOP
    ...
  END LOOP;
END TEST_TABLE; -- end of procedure
/

Read more

我强烈建议您摆脱异常处理程序,而将其排除在大纲之外-您应该让任何异常流回到调用方。您不知道谁叫它甚至都启用了输出,因此很可能甚至看不到您要打印的消息。届时只有您可以处理和需要处理的异常。

答案 1 :(得分:2)

您需要在下面加上正确的引号(并在is之后加上一个PROCEDURE TEST_TABLE关键字“ 感谢Alex使我醒来”):

CREATE OR REPLACE PACKAGE BODY PKG_TEST_TABLE IS 
 PROCEDURE TEST_TABLE IS        

--This procedure will delete partitions for the following tables:
--TEST_TABLE
 BEGIN
  FOR cc IN
  (
  SELECT partition_name, high_value
  FROM user_tab_partitions
  WHERE table_name = 'TEST_TABLE'
  )    
  LOOP
   BEGIN               
     IF sysdate >= ADD_MONTHS(cc.high_value, 3) THEN                  
      EXECUTE IMMEDIATE                     
      'ALTER TABLE TEST_TABLE DROP PARTITION ' || cc.partition_name;                   
       Dbms_Output.Put_Line('Dropping partition is completed.');        
     END IF;
   END;
  END LOOP;

  EXCEPTION WHEN Others THEN Dbms_Output.Put_Line( SQLERRM );

 END TEST_TABLE;

END PKG_TEST_TABLE; 
/

有一点建议,对于软件包,请使用与PKG_TEST_TABLE之类的过程不同的名称,以防混淆。

编辑:当然,您需要在包装的主体部分之前为包装创建一个规格部分:

CREATE OR REPLACE PACKAGE PKG_TEST_TABLE IS 
 PROCEDURE TEST_TABLE;
END PKG_TEST_TABLE;
/