为什么PL / SQL块不能创建临时表?

时间:2015-11-29 12:40:36

标签: sql oracle plsql

我想用数据创建和填充临时表,以便在循环语句中处理它,如下所示:

DECLARE 
  cnt NUMBER;
BEGIN


  SELECT COUNT(tname) INTO cnt from tab where tname = 'MY_TEMP';
  IF (cnt > 0) THEN
    EXECUTE IMMEDIATE 'DROP TABLE MY_TEMP';
  END IF;

  EXECUTE IMMEDIATE 'CREATE GLOBAL TEMPORARY TABLE MY_TEMP (G NVARCHAR2(128), F NVARCHAR2(128), V NVARCHAR2(128)) ON COMMIT DELETE ROWS';  

  INSERT INTO MY_TEMP VALUES (N'G-value1', N'F-value1', N'V-value1');  
  INSERT INTO MY_TEMP VALUES (N'G-value2', N'F-value2', N'V-value2');  
  ...

  FOR record IN (SELECT G,F,V FROM MY_TEMP)
  LOOP

     ... Do something sophisticated with record.G, record.F, record.V 
  END LOOP;

  COMMIT;
END;

当我在PL-SQL Developer中运行这个脚本时,它告诉我第一个INSERT,MY_TEMP表或视图不存在,即使我的EXECUTE IMMEDIATE'CREATE GLOBAL TEMPORARY TABLE ...'语句似乎没有执行错误。我检查了脚本执行后表格列表中没有MY_TEMP表

当我单独运行EXECUTE IMMEDIATE'CREATE GLOBAL TEMPORARY TABLE ...'时,它运行正常并且真正创建了MY_TEMP表。在此之后,整个脚本运行正常。

如何在不手动预制MY_TEMP表的情况下使用此脚本?

5 个答案:

答案 0 :(得分:4)

  

如何在不手动预制MY_TEMP表的情况下使用此脚本?

你做不到。当然,除非您使用EXECUTE IMMEDIATE创建临时表后运行所有内容。但我不能再推荐这种方法。

关键不在于您的脚本无法运行,而是它无法编译。如果无法首先编译它,Oracle将不会开始运行您的块。在Oracle尝试编译PL / SQL块时,该表不存在。您有编译错误,而不是运行时错误。

我怀疑您更熟悉SQL Server中的临时表,并且尝试以相同的方式在Oracle中使用临时表。如果是这种情况,那么您需要知道Oracle和SQL Server中的临时表之间存在差异。

首先,Oracle中没有本地临时表(即只有一个连接用户可见的表)。 Oracle确实有全局临时表,但只有全局临时表中的数据才是临时表。表本身是永久性的,因此一旦创建它,​​只有在您明确删除它时才会被删除。将其与SQL Server临时表进行比较,一旦所有相关用户断开连接,就会删除它们。

我真的认为你不需要在你的块中创建临时表。事先创建一次就足够了。

答案 1 :(得分:0)

为什么要删除并创建临时表?只需创建并使用它。

答案 2 :(得分:0)

在Oracle中创建临时表不是最佳做法,而是使用PIVOT

答案 3 :(得分:0)

The only way around for your problem is to make the whole INSERT INTO temp_table statements into EXECUTE IMMEDIATE in this way you can BYPASS the TABLE check during COMPILE Time first.
But this way in my opinion is not good at all. There are some questions in my mind which has be answred before answering this question.

1) Why Temp Table is created evertime and Dropped. 
We have option in GTT to keep or Remove Data after one Oracle Session.
2) Is this script a one time job ? If Yes then we can go for once GTT creation and the rest script will work fine.

答案 4 :(得分:0)

问:你的第一次插入不是问题。这是你的块的编译。该表不存在,但您正在引用它。尝试创建它,因为它就像是一旦bloick完成它就会存在。现在代码可能会在运行时存在对表的引用进行编译。

然而,当你的代码在桌面上有一个共享锁定时你会遇到问题,所以你不能放弃它。

您必须使您的选择动态化,或者确保创建表并将其删除到块的执行之外。