Skip to Main Content

Breadcrumb

Question and Answer

Chris Saxon

Thanks for the question, amr.

Asked: October 24, 2016 - 1:54 pm UTC

Last updated: November 03, 2016 - 8:45 pm UTC

Version: oracle 11g

Viewed 1000+ times

You Asked

Hi,
i was use sybase and connect to it with third party name (SAP business object - Desktop intelligent) but now we decide to use oracle instead of sybase but i found problem , most script which i was run in sybase has Temp table like that
------------------------------------------
select * from X1 into #TT1
select * from X2 into #TT2
select * from X3 into #TT3
select * from #TT1 join #TT2 into #TT4
select * from #TT3 join #TT4 where (****)
--------------------------------------
so most our work depend on temp table
i try to do same in oracle its not accept which mean
**create GLOBAL TEMPORARY TABLE TT1 on commit preserve rows AS
select * from X1**
thats code work good i try to do nest step **select * from TT1
say no data to fetch why
my question here
are you oracle database support temp table from third party or not ??
if not can work with stored procedure??
if yes how i can write same similar code as shown above inside stored procedure and give me same output??

and Chris said...

Oracle doesn't support creating "on-the-fly" temporary tables in the same way other databases do.

If you want to use global temporary tables you need to:

- Create it (this is a one-off operation)
- Load the data in
- Select the data back out

For example:

create global temporary table gtt (
  x int,
  y date
);

insert into gtt
  select rownum x, sysdate+rownum y from dual connect by level <= 10;

select * from gtt;

X   Y                     
1   25-OCT-2016 08:39:57  
2   26-OCT-2016 08:39:57  
3   27-OCT-2016 08:39:57  
4   28-OCT-2016 08:39:57  
5   29-OCT-2016 08:39:57  
6   30-OCT-2016 08:39:57  
7   31-OCT-2016 08:39:57  
8   01-NOV-2016 08:39:57  
9   02-NOV-2016 08:39:57  
10  03-NOV-2016 08:39:57 


Global temporary tables are best suited to cases where you'll use them over and over. Creating them for one-off queries is not a good idea.

You can "sort of" create temporary tables using the with clause and the materailize hint. This stores the results of the query in the with clause. See the SYS_TEMP_... table in the plan below:

set serveroutput off
with temp as (
  select /*+ materialize gather_plan_statistics */rownum x from dual connect by level <= 10
)
  select * from temp;

X   
1   
2   
3   
4   
5   
6   
7   
8   
9   
10 
 
select * from table(dbms_xplan.display_cursor(null, null, 'BASIC LAST'));

PLAN_TABLE_OUTPUT                                                         
EXPLAINED SQL STATEMENT:                                                  
------------------------                                                  
with temp as (   select /*+ materialize gather_plan_statistics */rownum   
x from dual connect by level <= 10 )   select * from temp                 
                                                                          
Plan hash value: 3256878401                                               
                                                                          
----------------------------------------------------------------------    
| Id  | Operation                       | Name                       |    
----------------------------------------------------------------------    
|   0 | SELECT STATEMENT                |                            |    
|   1 |  TEMP TABLE TRANSFORMATION      |                            |    
|   2 |   LOAD AS SELECT                |                            |    
|   3 |    COUNT                        |                            |    
|   4 |     CONNECT BY WITHOUT FILTERING|                            |    
|   5 |      FAST DUAL                  |                            |    
|   6 |   VIEW                          |                            |    
|   7 |    TABLE ACCESS FULL            | SYS_TEMP_0FD9D6606_2179062 |    
----------------------------------------------------------------------


Note this is undocumented, so not officially supported and is best avoided. But it is referenced in some MOS notes.

The optimizer may choose to create the temporary table for you anyway (without the hint).

Rating

  (3 ratings)

Is this answer out of date? If it is, please let us know via a Comment

Comments

amr Asd, October 29, 2016 - 5:43 pm UTC

thank you for your response
but i am still don't have answer to my problem still my code doesn't slution to be run on oracle by other words
can convert this code to be run inside stored procedure

Chris Saxon
October 31, 2016 - 12:57 pm UTC

Oracle doesn't have temp tables in the same way other RDBMSes do. If you want to use these, create your global temporary tables first. Then load your data in.

You can run any SQL inside a PL/SQL stored procedure. That's the beauty of it!

Wretched code

Duke Ganote, October 31, 2016 - 5:19 pm UTC

Of course, it can be done, but may qualify as "worst practice":

SQL> ed
Wrote file c:/users/DGANOTE/sqlplusedit.sql

  1  DECLARE x integer;
  2  BEGIN
  3    SELECT count(*) INTO x
  4      FROM user_tables;
  5    DBMS_OUTPUT.PUT_LINE('start: # tables = '||X);
  6    FOR rec IN ( SELECT table_name FROM user_tables
  7                  WHERE table_name like '#TT%'
  8                  ORDER BY 1 )  LOOP
  9     EXECUTE IMMEDIATE 'drop table "'||rec.table_name||'"';
 10    END LOOP;
 11    EXECUTE IMMEDIATE 'create table "#TT1" AS SELECT * FROM user_objects';
 12    EXECUTE IMMEDIATE 'create table "#TT2" AS SELECT view_name FROM user_views';
 13    EXECUTE IMMEDIATE 'create table "#TT3" AS SELECT * FROM user_tables';
 14    EXECUTE IMMEDIATE 'create table "#TT4" AS SELECT object_name FROM "#TT1"'
 15      ||' JOIN "#TT2" ON object_name = view_name';
 16    DBMS_OUTPUT.PUT_LINE('almost: # views = '||SQL%ROWCOUNT);
 17    EXECUTE IMMEDIATE 'create table "#TT5" AS SELECT object_name FROM "#TT1"'
 18      ||' JOIN "#TT3" ON object_name = table_name';
 19    DBMS_OUTPUT.PUT_LINE('finish: # tables = '||SQL%ROWCOUNT);
 20* END;
SQL> /
start: # tables = 85
almost: # views = 19
finish: # tables = 81

PL/SQL procedure successfully completed.


I don't generally use temp tables. I retain my 'work tables' -- just in case there are later questions. For example, during the day after the users have started to use the results, they may wonder about the results.

If it's important enough to stick in a table, it's important enough it keep around.
Connor McDonald
October 31, 2016 - 11:22 pm UTC

"If it's important enough to stick in a table, it's important enough it keep around. "

Nice quote!

amr Asd, November 03, 2016 - 10:46 am UTC

many thanks for your replay
now i write code to do it in stored procedure and i drop all TEMP table before procedure end to can run it again
but when i drop table the select statement which contain output say table does not exist although i making select statement before drop statement as below

create or replace PROCEDURE IU_DOWN ( IUD OUT sys_refcursor ) IS

stmt1 VARCHAR2(2000);

stmt2 VARCHAR2(2000);

stmt3 VARCHAR2(2000);

stmt4 VARCHAR2(2000);

stmt5 VARCHAR2(2000);

stmt6 VARCHAR2(2000);

stmt7 VARCHAR2(2000);

BEGIN



stmt1 :='create GLOBAL TEMPORARY table TT1 on COMMIT PRESERVE ROWS AS

select DATETIME "TIME",extract(day from DATETIME)"DAYID",TO_CHAR(DATETIME,''HH24'')"HOURID",RNC"RNC",NODE_B"NENAME",AVA"AVA",

case when instr(upper(NODE_B),''('',1)>0 then substr(upper(NODE_B),1,instr(upper(NODE_B),''('',1))

else substr(upper(NODE_B),1,length(NODE_B)) end "TEST"

from NODE_B_AVA

where AVA=0

and extract(day from DATETIME) >= extract(day from sysdate -2)';

stmt2 :='create GLOBAL TEMPORARY table TT2 on COMMIT PRESERVE ROWS AS

select TIME,DAYID,HOURID,RNC,TEST,

case when instr(upper(TEST),''CAI'',1)>0 then substr(upper(TEST),instr(upper(TEST),''CAI'',1),7)

when instr(upper(TEST),''UPP'',1)>0 then substr(upper(TEST),instr(upper(TEST),''UPP'',1),7)

when instr(upper(TEST),''DEL'',1)>0 then substr(upper(TEST),instr(upper(TEST),''DEL'',1),7)

when instr(upper(TEST),''SIN'',1)>0 then substr(upper(TEST),instr(upper(TEST),''SIN'',1),7)

when instr(upper(TEST),''ALX'',1)>0 then substr(upper(TEST),instr(upper(TEST),''ALX'',1),7)

else ''Other'' end Site_ID

from TT1';

stmt3 :='create GLOBAL TEMPORARY table TT3 on COMMIT PRESERVE ROWS AS

select DATETIME "TIME",extract(day from DATETIME)"DAYID",TO_CHAR(DATETIME,''HH24'')"HOURID",NENAME"NENAME",NODEB"NODEB",IU_UL"UL",IU_DL"DL",

case when instr(upper(NENAME),''('',1)>0 then substr(upper(NENAME),1,instr(upper(NENAME),''('',1))

else substr(upper(NENAME),1,length(NENAME)) end "TEST"

from IUB_DROP

where IU_DL>5000

and extract(day from DATETIME) >= extract(day from sysdate -2)';

stmt4 :='create GLOBAL TEMPORARY table TT4 on COMMIT PRESERVE ROWS AS

select Time,DAYID,HOURID,NENAME,UL,DL,

case when instr(upper(TEST),''CAI'',1)>0 then substr(upper(TEST),instr(upper(TEST),''CAI'',1),7)

when instr(upper(TEST),''UPP'',1)>0 then substr(upper(TEST),instr(upper(TEST),''UPP'',1),7)

when instr(upper(TEST),''DEL'',1)>0 then substr(upper(TEST),instr(upper(TEST),''DEL'',1),7)

when instr(upper(TEST),''SIN'',1)>0 then substr(upper(TEST),instr(upper(TEST),''SIN'',1),7)

when instr(upper(TEST),''ALX'',1)>0 then substr(upper(TEST),instr(upper(TEST),''ALX'',1),7)

else ''Other'' end Site_ID

from TT3';

stmt5 :='create GLOBAL TEMPORARY table TT5 on COMMIT PRESERVE ROWS AS

select a.TIME,a.DAYID,a.HOURID,a.Site_ID,b.RNC

from TT4 a , TT2 b

where a.TIME=b.TIME

and a.Site_ID=b.Site_ID';

stmt6 :='create GLOBAL TEMPORARY table TT6 on COMMIT PRESERVE ROWS AS

select SITE_ID,RNC,DAYID from TT5 group by SITE_ID,RNC,DAYID having count(HOURID)>3';

stmt7 :='OPEN IUD for select SITE_ID,RNC from TT6 GROUP BY SITE_ID,RNC having COUNT(*)>=1';

EXECUTE IMMEDIATE stmt1;

EXECUTE IMMEDIATE stmt2;

EXECUTE IMMEDIATE stmt3;

EXECUTE IMMEDIATE stmt4;

EXECUTE IMMEDIATE stmt5;

EXECUTE IMMEDIATE stmt6;

--EXECUTE IMMEDIATE stmt7;

OPEN IUD for select SITE_ID,RNC from TT6 GROUP BY SITE_ID,RNC having COUNT(*)>=1;

EXECUTE IMMEDIATE 'truncate table TT1';

EXECUTE IMMEDIATE 'drop table TT1';

EXECUTE IMMEDIATE 'truncate table TT2';

EXECUTE IMMEDIATE 'drop table TT2';

EXECUTE IMMEDIATE 'truncate table TT3';

EXECUTE IMMEDIATE 'drop table TT3';

EXECUTE IMMEDIATE 'truncate table TT4';

EXECUTE IMMEDIATE 'drop table TT4';

EXECUTE IMMEDIATE 'truncate table TT5';

EXECUTE IMMEDIATE 'drop table TT5';

EXECUTE IMMEDIATE 'truncate table TT6';

EXECUTE IMMEDIATE 'drop table TT6';

END IU_DOWN;

*******again thanks for replay ************

Chris Saxon
November 03, 2016 - 8:45 pm UTC

You're dropping the source of the data! The refcursor has nowhere to get its data from.

This is just one reason creating and dropping temp tables like this is a bad idea. If you really need to use GTTs, create them once. Not each time you call the procedure. Your PL/SQL should just insert data.

More to Explore

PL/SQL demos

Check out more PL/SQL tutorials on our LiveSQL tool.

PL/SQL docs

PL/SQL reference manual from the Oracle documentation library