问题
I'm trying to create a temporary table within a Stored Procedure to perform multiple operations on it and then execute a select statement. I haven't had success using global temporary tables. When I execute the code below I get an ORA-00942 error
(table or view does not exists). I must return the cursor to use it in Spring. Any ideas?
PROCEDURE DELETME (
O_CURSOR OUT tCursor,
COD_ERROR OUT NUMBER,
MSM_ERROR OUT VARCHAR2
)
AS
BEGIN
execute immediate 'create global temporary table my_temp_table(column1 number) on commit delete rows';
insert into my_temp_table(column1) values (1);
COD_ERROR := 1;
OPEN o_cursor FOR
select * from my_temp_table;
EXCEPTION
WHEN OTHERS THEN
COD_ERROR:=0;
MSM_ERROR:=dbms_utility.format_error_backtrace ||' '||SQLERRM;
END DELETME;
回答1:
Your procedure won't compile because you have dependencies on TEMP_TABLE which does not exist. Hence the ora-00942
. Of course, if it does exist then your procedure will fail at runtime: the create global temporary table
call will fail, because the table already exists.
Basically you have misunderstood the purpose of global temporary tables in Oracle. They are permanent structures, it is just the data they hold which is transient. This is a common issue, especially for people who are familiar with SQL Server and are trying to convert T-SQL into Oracle. Temporary tables in MSSQL are more like PL/SQL collections.
Obviously your posted code is a toy so it's not clear why you think you need a temporary table. It's quite likely that you don't, as Oracle SQL is pretty powerful. Chances are you can just open a ref cursor for a complex SELECT statement.
But it you do happen to have some real need this is how to do it:
First, as a one-off exercise:
create global temporary table my_temp_table
(column1 number) on commit delete rows
tablespace temporary_ts;
Note the tablespace clause: GTTs write to disk not memory, which means they are slow to populate and slow to read. If you're going to use GTTs it's a good idea to have a dedicated temporary tablespace just for them, because they have a different usage profile compare to other temporary processes such as sorts.
Anyway, your procedure becomes
PROCEDURE DELETME (
O_CURSOR OUT tCursor,
COD_ERROR OUT NUMBER,
MSM_ERROR OUT VARCHAR2
)
AS
BEGIN
insert into my_temp_table(column1) values (1);
COD_ERROR := 1;
OPEN o_cursor FOR
select * from my_temp_table;
EXCEPTION
WHEN OTHERS THEN
COD_ERROR:=0;
MSM_ERROR:=dbms_utility.format_error_backtrace ||' '||SQLERRM;
END DELETME;
Remember you need to issue a commit (or rollback) to clear your table; if you don't housekeep it that may create problems when the same session re-uses it.
Alternatively, use a collection instead. Collections are much faster, because they are memory structures. Although the memory comes from session allocations so this is not the best solution if the total number of rows is too large.
Something like this. Again, as a one-off exercise:
create or replace object num_nt as table of number;
Then your procedure becomes:
PROCEDURE DELETME (
O_CURSOR OUT tCursor,
COD_ERROR OUT NUMBER,
MSM_ERROR OUT VARCHAR2
)
AS
local_nt num_nt;
BEGIN
select 1
bulk collect into local_nt
from dual;
COD_ERROR := 1;
OPEN o_cursor FOR
select * from table(local_nt);
EXCEPTION
WHEN OTHERS THEN
COD_ERROR:=0;
MSM_ERROR:=dbms_utility.format_error_backtrace ||' '||SQLERRM;
END DELETME;
There is a third "solution" which is to use dynamic SQL for all the calls in the procedure. This is a really bad approach (even apart from misunderstanding the use of global temporary tables). Dynamic code is flakier than regular code, and should only be used when really necessary. Executing DDL is expensive and not something to be done as part of standard business processing; also it complicates transactions.
回答2:
You can not compile procedure because table does not exist yet. You can either:
execute immediate 'insert into my_temp_table(column1) values (:x)' using 1.
Oracle docs about EXECUTE IMMEDIATE http://docs.oracle.com/database/122/LNPLS/EXECUTE-IMMEDIATE-statement.htm#LNPLS01317
NOTE: Written from head, not tested
来源:https://stackoverflow.com/questions/41689135/how-to-create-a-temporary-table-inside-stored-procedure-before-opening-a-cursor