oracle执行立即不执行

时间:2013-11-06 19:11:14

标签: plsql oracle11g

我是Oracle(11gr2)的新手,我有以下脚本:

BEGIN
    DECLARE 
        source varchar2(1);

    BEGIN
        dbms_output.enable;


        BEGIN
            EXECUTE IMMEDIATE 'DROP VIEW SP_AD;';
            SELECT SOURCE INTO source FROM map_switch WHERE ROWNUM = 1;
            IF source = 'A' 
                THEN 
                    EXECUTE IMMEDIATE 'DROP TABLE SP_AD_B;';
                    EXECUTE IMMEDIATE 'RENAME TABLE SP_AD_A TO SP_AD;';
                ELSE 
                    EXECUTE IMMEDIATE 'DROP TABLE SP_AD_A;';
                    EXECUTE IMMEDIATE 'RENAME TABLE SP_AD_B TO SP_AD;';
            END IF;
            COMMIT WORK;
                    dbms_output.put_line('SP_AD table issue fixed');
            EXCEPTION
                WHEN OTHERS THEN
                    dbms_output.put_line('Exception, rolling back transaction, SP_AD not resolved.');
                    ROLLBACK WORK;
        END;        
    END;
END;
/

基本上,它确定要删除哪个表,然后删除视图并重命名另一个表。

如果我单独运行语句,它可以很好地工作,但在上面的脚本中,它返回成功执行但没有执行的程序。

我怀疑它因为一些奇怪的原因而回滚,但我在没有回滚的情况下犹豫不决(这些表有超过300,000条记录)。

有人可以告诉我什么是错的,而且我的异常块有什么问题吗?

1 个答案:

答案 0 :(得分:6)

正如评论者所指出的,有几个原因导致您的代码无法按预期运行。

首先,不要在传递给EXECUTE IMMEDIATE的字符串中使用分号,因为这样做会给你一个ORA-00911'无效字符'错误:

SQL> BEGIN
  2    EXECUTE IMMEDIATE 'DROP TABLE SP_AD_B;';
  3  END;
  4  /
BEGIN
*
ERROR at line 1:
ORA-00911: invalid character
ORA-06512: at line 2

运行此功能后,您可以验证该表是否仍然存在:

SQL> SELECT * FROM SP_AD_B;

no rows selected

(我没有你的表SP_AD_B,所以我刚刚创建了一个名为SP_AD_B的表,其中包含一个整数列。我没有在其中添加任何数据。)

如果删除字符串中的分号,而不是外部的分号,则可以使用分号:

SQL> BEGIN
  2    EXECUTE IMMEDIATE 'DROP TABLE SP_AD_B';
  3  END;
  4  /

PL/SQL procedure successfully completed.

SQL> SELECT * FROM SP_AD_B;
SELECT * FROM SP_AD_B
              *
ERROR at line 1:
ORA-00942: table or view does not exist

现在表格已经消失,我们在尝试查询时遇到错误。

希望这应该允许您修复脚本以使其正常工作并删除相关表。

但是为什么你的输出信息中没有得到任何有用的信息?好吧,让我们重新创建SP_AD_B表,并重新引入分号,并尝试再次删除表,但使用与您类似的EXCEPTION处理程序:

SQL> BEGIN
  2    EXECUTE IMMEDIATE 'DROP TABLE SP_AD_B;';
  3  EXCEPTION
  4    WHEN OTHERS THEN
  5      dbms_output.put_line('Exception, rolling back transaction, SP_AD not resolved.');
  6  END;
  7  /
Exception, rolling back transaction, SP_AD not resolved.

PL/SQL procedure successfully completed.

在这种情况下,我们收到一条错误消息,告诉我们出错了,所以表格没有丢弃。但 出了什么问题? Oracle可以报告数千个错误,如果不知道错误消息,很难猜出问题是什么。

您可以在此处采取多种方法。首先,您可以在SQLERRMdbms_output

中编写错误消息
SQL> BEGIN
  2    EXECUTE IMMEDIATE 'DROP TABLE SP_AD_B;';
  3  EXCEPTION
  4    WHEN OTHERS THEN
  5      dbms_output.put_line('Exception, rolling back transaction, SP_AD not resolved.');
  6      dbms_output.put_line('Error message was: ' || SQLERRM);
  7  END;
  8  /
Exception, rolling back transaction, SP_AD not resolved.
Error message was: ORA-00911: invalid character

PL/SQL procedure successfully completed.

如果您愿意,也可以使用dbms_utility.format_error_backtrace将当前堆栈跟踪作为字符串返回。这可能会帮助您找出错误的来源。

或者,您可以重新加载例外。在RAISE处理程序中单独使用EXCEPTION会重新引发当前异常:

SQL> BEGIN
  2    EXECUTE IMMEDIATE 'DROP TABLE SP_AD_B;';
  3  EXCEPTION
  4    WHEN OTHERS THEN
  5      dbms_output.put_line('Exception, rolling back transaction, SP_AD not resolved.');
  6      RAISE;
  7  END;
  8  /
Exception, rolling back transaction, SP_AD not resolved.
BEGIN
*
ERROR at line 1:
ORA-00911: invalid character
ORA-06512: at line 6

但是,鉴于你的EXCEPTION处理程序并没有真正做任何有用的事情,最好的方法很可能完全摆脱它。

您的异常处理程序无法实现任何功能,因为您无法提交或回滚CREATEALTERDROPTRUNCATE等DDL语句。这些语句中的每一个都在运行之前和之后立即发出COMMIT。如果DROP成功但RENAME失败,则无法通过回滚事务来获取已删除的表。我建议您删除COMMIT WORKROLLBACK WORK语句。

最后,评论者Jeffrey Kemp注意到这一行:

SELECT SOURCE INTO source FROM map_switch WHERE ROWNUM = 1;

这将从表source 的某些任意行中将SOURCE 列的值分配给名为map_switch的变量。它可以是任何一行;因为您没有指定任何排序,Oracle可以自由地订购map_switch行,但它喜欢。

如果表格中只有一行,那么您可以清楚地找到哪一行。但是,如果是这种情况,为什么要指定ROWNUM = 1?该表是否有多行,并且ROWNUM = 1部分是否可以使“确切的提取返回超过请求的行数”错误?

你最好做以下事情:

SELECT SOURCE INTO source
  FROM (SELECT SOURCE FROM map_switch ORDER BY some_column)
 WHERE ROWNUM = 1;

我不知道您的map_switch表格中有哪些列,所以我刚刚使用上面的some_column作为其中一个的占位符。如果可能,请选择具有唯一值的列。

请注意,我们不能简单地执行SELECT ... WHERE ROWNUM = 1 ORDER BY some_column因为在执行排序之前应用ROWNUM = 1子句,并且没有很多点对单行进行排序,因为它只能有一个顺序被退回。