1

我是 Oracle 的新手,我正在为此苦苦挣扎:

DECLARE 
 cnt NUMBER;

BEGIN
 SELECT COUNT(*) INTO cnt FROM all_tables WHERE table_name like 'Newtable'; 
 IF(cnt=0) THEN
   EXECUTE IMMEDIATE 'CREATE TABLE Newtable ....etc';
 END IF;
 COMMIT;

 SELECT COUNT(*) INTO cnt FROM Newtable where id='something'
 IF (cnt=0) THEN
   EXECUTE IMMEDIATE 'INSERT INTO Newtable ....etc';
 END IF;
END;

这不断崩溃,并在插入行上给我“PL/SQL:ORA-00942:表或视图不存在”。我怎样才能避免这种情况?或者我做错了什么?我希望这两个语句(实际上它当然更多)在一个事务中。

4

3 回答 3

4

这不是insert问题所在,而是select之前的两行。块中有三个语句,而不是两个。您正在从尚不存在的同一个新表中进行选择。您已经insert通过使该动态避免了这种情况,但是您需要对选择执行相同的操作:

 EXECUTE IMMEDIATE q'[SELECT COUNT(*) FROM Newtable where id='something']'
 INTO cnt;

SQL 小提琴

不过,在运行时创建表似乎是错误的。您说“出于安全问题,该表只有在填充了正确的数据集时才能存在”,这对我来说并不完全有意义 - 即使这个块是一次性创建和填充它,任何依赖它的东西都会失败或在此运行之前无效。如果这是模式创建的一部分,那么使其动态化似乎并没有增加太多。您还说您希望两者都发生在一个事务中,但是 DDL 将执行隐式提交,您无法回滚 DDL,并且您的手动提交无论如何都会为插入启动一个新事务。也许您的意思是如果表创建失败,则插入不应该发生 - 但无论如何它们都会失败,无论它们是否在同一个块中。无论如何,这似乎有点奇怪。

此外,all_tables用于检查仍可能导致其行为异常。如果该表存在于另一个模式中,您create将被跳过,但您select可能insert仍然会失败,因为他们可能无法看到或不会查找其他模式版本。使用user_tables或添加owner检查可能会更安全一些。

于 2013-08-14T14:10:49.973 回答
0

Oracle 分两步处理块的执行:

  1. 首先,它解析块并以内部表示形式编译它(所谓的“P 代码”)
  2. 然后它运行 P 代码(它可能被解释或编译为机器代码,具体取决于您的架构和 Oracle 版本)

为了编译代码,Oracle 必须知道引用表的名称(和模式!)。您的表还不存在,因此没有架构并且代码无法编译。

对于您在一项大事务中创建表的意图:这行不通。Oracle 总是在 DDL 语句(, , (!) 等)之前和之后隐式提交当前事务。所以在每个 之后,Oracle 都会提交当前事务并启动一个新事务。create tablealter tabletruncate tablecreate table

于 2013-08-14T14:22:14.920 回答
0

尝试以下方法,即创建和插入在两个不同的块中

DECLARE
    cnt NUMBER;
BEGIN
    SELECT  COUNT (*)
      INTO  cnt
      FROM  all_tables
     WHERE  table_name LIKE 'Newtable';

    IF (cnt = 0)
    THEN
        EXECUTE IMMEDIATE 'CREATE TABLE Newtable(c1 varchar2(256))';
    END IF;
END;

DECLARE
    cnt2    NUMBER;
BEGIN
    SELECT  COUNT (*)
      INTO  cnt2
      FROM  newtable
     WHERE  c1 = 'jack';

    IF (cnt2 = 0)
    THEN
        EXECUTE IMMEDIATE 'INSERT INTO Newtable values(''jill'')';
    END IF;
END;
于 2013-08-14T10:24:18.347 回答