我是SQL Server用户,我有一个使用Oracle的小项目,所以我试图了解Oracle的一些特性,我认为我需要一些帮助才能更好地理解以下情况:
我想在创建临时表之前测试它是否存在,所以我在这里有这个代码:
DECLARE
table_count INTEGER;
var_sql VARCHAR2(1000) := 'create GLOBAL TEMPORARY table TEST (
hello varchar(1000) NOT NULL)';
BEGIN
SELECT COUNT(*) INTO table_count FROM all_tables WHERE table_name = 'TEST';
IF table_count = 0 THEN
EXECUTE IMMEDIATE var_sql;
END IF;
END;
它正常工作,所以在我执行一次后,我在我的IF上添加了一个else语句:
ELSE
insert into test (hello) values ('hi');
再次执行它并在我的测试表中添加了一行。
好的,我的代码已经准备就绪,所以我删除了临时表并尝试再次运行整个语句,但是当我这样做时,我收到以下错误:
ORA-06550: line 11, column 19:
PL/SQL: ORA-00942: table or view does not exist
ORA-06550: line 11, column 7:
PL/SQL: SQL Statement ignored
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
然后我将我的else语句改为this,现在它再次起作用:
ELSE
EXECUTE IMMEDIATE 'insert into test (hello) values (''hi'')';
我的问题是为什么单独运行我可以简单地使用insert而不是EXECUTE IMMEDIATE以及为什么我的SELECT语句在BEGIN之后仍然可以工作时所有其余部分似乎需要EXECUTE IMMEDIATE才能正常运行?
答案 0 :(得分:7)
整个PL / SQL块在编译时被解析,但动态语句中的文本直到运行时才被计算。 (对于匿名块,它们接近同样的事情,但仍然是不同的步骤。)
您的if / else在运行时之前也不会被评估。编译器不知道在插入时表总是存在,它只能在它解析整个块时检查它是否存在。
如果表已经存在则可以;编译器可以看到它,块执行,你的select得到1,然后你进入else进行插入。但是如果它不存在那么在编译时ORA-00942 正确解析插入错误并且块中没有任何内容被执行。
由于表创建是动态的,因此对表的所有引用也必须是动态的 - 您看到的插入,但是如果您再查询它。基本上它会使您的代码更难以阅读并且可以隐藏语法错误 - 因为动态代码直到运行时才被解析,并且您可能在分支中的动态语句中有错误很长一段时间。
无论如何都不应该动态创建全局temporary tables。它们是具有临时数据的永久对象,特定于每个会话,不应作为应用程序代码的一部分创建/删除。 (一般情况下,您的应用程序不应进行架构更改;它们应限于升级/维护更改并进行控制,以避免错误,数据丢失和意外的副作用; GTT也不例外。)
与某些其他关系数据库中的临时表不同,在Oracle数据库中创建临时表时,可以创建静态表定义。临时表是数据字典中描述的持久对象,但在会话将数据插入表中之前显示为空。您可以为数据库本身创建一个临时表,而不是为每个PL / SQL存储过程创建一个临时表。
创建一次GTT并使所有PL / SQL代码保持静态。如果您想要更接近SQL Server本地临时表的内容,请查看PL/SQL collections。
答案 1 :(得分:3)
PL / SQL:ORA-00942:表或视图不存在
这是编译时错误,即在创建GTT之前解析静态SQL时。
让我们看看编译时间和运行时间错误之间的区别:
静态SQL:
SQL> DECLARE
2 v number;
3 BEGIN
4 select empno into v from a;
5 end;
6 /
select empno into v from a;
*
ERROR at line 4:
ORA-06550: line 4, column 26:
PL/SQL: ORA-00942: table or view does not exist
ORA-06550: line 4, column 1:
PL/SQL: SQL Statement ignored
动态SQL:
SQL> DECLARE
2 v number;
3 BEGIN
4 execute immediate 'select empno from a' into v;
5 end;
6 /
DECLARE
*
ERROR at line 1:
ORA-00942: table or view does not exist
ORA-06512: at line 4
在第一个PL / SQL块中,编译时进行了语义检查,您可以看到PL/SQL: ORA-00942: table or view does not exist
。在第二个PL / SQL块中,您没有看到PL / SQL错误。
底线,
在编译时,不知道表是否存在 仅在运行时创建。
在您的情况下,为避免此行为,您需要使 INSERT 也动态并使用 EXECUTE IMMEDIATE 。这样,您可以逃避编译时错误并获取动态创建的表,并在运行时动态插入。
话虽如此,基本的问题是你正在尝试动态创建 GTT ,这不是一个好主意。你应该创建一次,并按照你想要的方式使用它。
答案 2 :(得分:-2)
我已经修改了你的代码,并且就逻辑而言它起作用。但是因为exp [在早期的帖子中运行在运行时动态创建GTT根本不是一个好主意。
--- Firstly by dropping the table i.e NO TABLE EXISTS in the DB in AVROY
SET serveroutput ON;
DECLARE
table_count INTEGER;
var_sql VARCHAR2(1000) := 'create GLOBAL TEMPORARY table TEST (
hello varchar(1000) NOT NULL)';
BEGIN
EXECUTE IMMEDIATE 'DROP TABLE AVROY.TEST'; --Added the line just to drop the table as per your comments
SELECT COUNT(*)
INTO table_count
FROM all_tables
WHERE table_name = 'TEST'
AND OWNER = 'AVROY';
IF table_count = 0 THEN
EXECUTE IMMEDIATE var_sql;
dbms_output.put_line('table created');
ELSE
INSERT INTO AVROY.test
(hello
) VALUES
('hi'
);
END IF;
END;
--------------------OUTPUT-----------------------------------------------
anonymous block completed
table created
SELECT COUNT(*)
-- INTO table_count
FROM all_tables
WHERE table_name = 'TEST'
AND OWNER = 'AVROY';
COUNT(*)
------
1
--------
-- Second option is without DROPPING TABLE
SET serveroutput ON;
DECLARE
table_count INTEGER;
var_sql VARCHAR2(1000) := 'create GLOBAL TEMPORARY table TEST (
hello varchar(1000) NOT NULL)';
BEGIN
--EXECUTE IMMEDIATE 'DROP TABLE AVROY.TEST';
SELECT COUNT(*)
INTO table_count
FROM all_tables
WHERE table_name = 'TEST'
AND OWNER = 'AVROY';
IF table_count = 0 THEN
EXECUTE IMMEDIATE var_sql;
dbms_output.put_line('table created');
ELSE
INSERT INTO AVROY.test
(hello
) VALUES
('hi'
);
dbms_output.put_line(SQL%ROWCOUNT||' Rows inserted into the table');
END IF;
END;
-------------------------------OUTPUT-------------------------------------
anonymous block completed
1 Rows inserted into the table
---------------------------------------------------------------------------