如何创建表并在同一语句中插入

时间:2013-08-14 09:17:29

标签: oracle

我是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:表或视图不存在”。我怎么能避免这个?或者我做错了什么?我希望在一次交易中这两个陈述(实际上它当然要多得多)。

3 个答案:

答案 0 :(得分:4)

问题不是insert,而是之前的select两行。块内有三个语句,而不是两个。您正在从尚不存在的相同新表中进行选择。你已经在insert中通过制作动态来避免这种情况,但你需要为选择做同样的事情:

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

SQL Fiddle

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

此外,使用all_tables进行检查仍可能导致此行为奇怪。如果该表存在于另一个架构中,则会跳过create,但您selectinsert可能仍会失败,因为他们可能无法查看或不会查找,另一个架构版本。使用user_tables或添加owner支票可能会更安全一些。

答案 1 :(得分: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;

答案 2 :(得分:0)

Oracle分两步处理块的执行:

  1. 首先,它解析块并以内部表示形式编译它(所谓的“P代码”)
  2. 然后运行P代码(可能会被解释或编译为机器代码,具体取决于您的架构和Oracle版本)
  3. 为了编译代码,Oracle必须知道引用表的名称(和架构!)。您的表尚不存在,因此没有架构,代码也无法编译。

    您打算在一个大事务中创建表:这不起作用。 Oracle总是implicitly commits the current transaction before and after a DDL statementcreate tablealter tabletruncate table(!)等)。因此,在每个create table之后,Oracle将提交当前事务并启动一个新事务。