我是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:表或视图不存在”。我怎么能避免这个?或者我做错了什么?我希望在一次交易中这两个陈述(实际上它当然要多得多)。
答案 0 :(得分:4)
问题不是insert
,而是之前的select
两行。块内有三个语句,而不是两个。您正在从尚不存在的相同新表中进行选择。你已经在insert
中通过制作动态来避免这种情况,但你需要为选择做同样的事情:
EXECUTE IMMEDIATE q'[SELECT COUNT(*) FROM Newtable where id='something']'
INTO cnt;
在运行时创建表似乎是错误的。你说'出于安全问题,表只有在填充了正确的数据集时才能存在',这对我来说并不完全有意义 - 即使这个块一次创建并填充它,任何依赖它的东西都会失败或者在此运行之前无效。如果这是模式创建的一部分,那么使其动态似乎并没有增加太多。您还说过,您希望两者都发生在一个事务中,但DDL将执行隐式提交,您无法回滚DDL,并且您的手动提交将为插件启动新事务。也许你的意思是如果表创建失败,插入不应该发生 - 但无论如何它们都会失败,无论它们是否在同一个块中。无论如何,这似乎有点奇怪。
此外,使用all_tables
进行检查仍可能导致此行为奇怪。如果该表存在于另一个架构中,则会跳过create
,但您select
和insert
可能仍会失败,因为他们可能无法查看或不会查找,另一个架构版本。使用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分两步处理块的执行:
为了编译代码,Oracle必须知道引用表的名称(和架构!)。您的表尚不存在,因此没有架构,代码也无法编译。
您打算在一个大事务中创建表:这不起作用。 Oracle总是implicitly commits the current transaction before and after a DDL statement(create table
,alter table
,truncate table
(!)等)。因此,在每个create table
之后,Oracle将提交当前事务并启动一个新事务。