How to use Oracle global temporary table? - oracle

I am attempting to use an Oracle global temporary table without physically creating a table in the database. The following code is not working. Can someone please explain the proper way to use global temporary tables?
declare
global temporary table my_temp_table(column1 number) on commit preserve rows;
begin
insert into my_temp_table (column1) values (1);
select * from my_temp_table;
end;

Try the below using execute immediate: it uses exception handler to bypass if table already exists; also note that you cannot use SQL select inside PLSQL
DECLARE
l_column1 number;
begin
begin
execute immediate 'create global temporary table my_temp_table(column1 number)
on commit preserve rows';
exception when others
then
dbms_output.put_line(sqlerrm);
end;
insert into my_temp_table (column1) values (1);
select * into l_column1 from my_temp_table where column1=1;
dbms_output.put_line('the temp value is '||l_column1);
end;

Unless you use EXECUTE IMMEDIATE you cannot create the table inside PL/SQL. Try this:
create global temporary table my_temp_table(column1 number) on commit preserve rows;
insert into my_temp_table (column1) values (1);
select * from my_temp_table;

Oracle global temp tables are a bit different than you might be expecting.
You need to create the table and declare it as a global temp table.
Here is a good resource:
http://www.oracle-base.com/articles/misc/temporary-tables.php

Related

Result of Stored Procedure save in table variable

I have question: I have stored procedure A(return three out paramters). I want to call procedure A in loop and insert these three parameters into temporaty table and return this table.
DECLARE
Type TestTable IS TABE OF NUMBER; -- for example one parameter!!!
myTable TestTable;
BEGIN
LOOP
A(o_param1, o_param2, o_param3);
-- myTable insert o_param1,2,3;
-- insert into myTable values(99); - here I have error PL/SQL: ORA-00942: table or view does not exist
END LOOP;
SELECT * FROM myTable;
END;
I dont know how to do -- myTable insert o_param1,2,3;. Please help me.
write insert statement inside the loop. so for each loop you can have the values inserted to the table and give a commit after the loop.
But you cannot have a select * from table inside the anonymous block. Remove that from the block and after end; you can try running select * from table to see the output.
BEGIN
LOOP
A(o_param1, o_param2, o_param3);
-- myTable insert o_param1,2,3;
insert into myTable values (o_param1, o_param2, o_param3);
END LOOP;
commit;
--SELECT * FROM myTable;-
END;
SELECT * FROM myTable;
> Blockquote
First, you cannot insert data into myTable directly (insert into myTable) because Oracle table types, declared in a declare section of the script, are not visible in sql statements (exception - insert using 'bulk collect' with types, declared in Oracle dictionary).
Even if you insert data in myTable using myTable(idx)... you can not select it outside the script because myTable exists only inside the script.
I think the simpliest way is to create usual table or global temporary table. If you will use global temporary table create it with 'ON COMMIT PRESERVE ROWS' (if you use commit after insert)

Table exists in stored procedure while used in select but not when Used in Insert statement

My stored procedure is like this:
create or replace procedure tpk.sp_Test_proc
IS
err_code NUMBER;
err_msg VARCHAR (500);
v_tbl_cnt NUMBER;
v_tbl_valid NUMBER;
Begin
SELECT COUNT(*) INTO v_tbl_cnt FROM USER_TABLES
WHERE TABLE_NAME IN (UPPER('Tbl1'),UPPER('tbl2'),UPPER('tbl3'));
IF(v_tbl_cnt =3) THEN
EXECUTE IMMEDIATE 'TRUNCATE TABLE Tbl1';
EXECUTE IMMEDIATE 'TRUNCATE TABLE Tbl2';
EXECUTE IMMEDIATE 'TRUNCATE TABLE Tbl3';
EXECUTE IMMEDIATE 'DROP TABLE Tbl1';
EXECUTE IMMEDIATE 'DROP TABLE Tbl2';
EXECUTE IMMEDIATE 'DROP TABLE Tbl3';
EXECUTE IMMEDIATE
'CREATE global temporary TABLE tbl1
( Id Integer... )'
Insert into tbl1
Select * from another_schema.Dw_table /* In this line it throws error Table does not exist */
end if;
end;
I tired same table with store procedure only to fetch the data its working there but when I used in Insert statement it throws an error
PL/SQL: ORA-00942 table or view does not exist.
I am totally confused - what's wrong here?
Select * from another_schema.Dw_table
You don't have a privilege to select from that table. Even if you think you do (granted via a role), it won't work in stored procedures - you have to grant it directly to user you're connected to.
Besides, there's no point in truncating tables first, and dropping them next. Just drop them.
Furthermore, there's rarely need to create tables dynamically (the way you do it), especially global temporary tables. Create them once, use them many times. No dropping. No (re)creating them in PL/SQL.

Can I directly define a trigger in all_triggers table on a table?

I am performing an archival process on a huge database and it involves deleting the production active table and renaming another table to be the new production table. When dropping the production active table, the triggers also get deleted. So I am just taking a backup of the triggers defined on my table using
select * from all_triggers where table_name=mytablename;
My question is, can I directly copy these triggers in to the all_triggers table after I rename my other table to be the new production active table? Will the triggers still work?
Same question for defining indexes and constraints too.
Copying the triggers from one table to another can be done by copying DDL, and not updating all_triggers table. This can be done by using DBMS_METADATA.
The closest practical example I found here: Copy Triggers when you Copy a Table
The following script can be amended as per your need:
declare
p_src_tbl varchar2(30):= 'PERSONS'; --your table name
p_trg_tbl varchar2(30):= 'PSN2'; --your trigger name
l_ddl varchar2(32000);
begin
execute immediate 'create table '||p_trg_tbl||' as select * from '||p_src_tbl||' where 1=2';
for trg in (select trigger_name from user_triggers where table_name = p_src_tbl) loop
l_ddl:= cast(replace(replace(dbms_metadata.get_ddl( 'TRIGGER', trg.trigger_name),p_src_tbl,p_trg_tbl),trg.trigger_name,substr(p_trg_tbl||trg.trigger_name, 1, 30)) as varchar2);
execute immediate substr(l_ddl, 1, instr(l_ddl,'ALTER TRIGGER')-1);
end loop;
end;
/
No, you cannot directly manipulate data dictionary tables. You can't insert data directly into all_triggers (the same goes for any data dictionary table). I guess you probably could given enough hacking. It just wouldn't work and would render your database unsupported.
The correct way to go is to script out your triggers and reapply them later. If you want to do this programmatically, you can use the dbms_metadata package. If you want to get the DDL for each of the triggers on a table, you can do something like
select dbms_metadata.get_ddl( 'TRIGGER', t.trigger_name, t.owner )
from all_triggers t
where table_owner = <<owner of table>>
and table_name = <<name of table>>
To replicate your scenario i have prepared below snippet. Let me know if this helps.
--Simple example to copy Trigger from one table to another
CREATE TABLE EMP_V1 AS
SELECT * FROM EMP;
--Creating Trigger on Old Table for Example purpose
CREATE OR REPLACE TRIGGER EMP_OLD_TRIGGER
AFTER INSERT OR UPDATE ON EMP FOR EACH ROW
DECLARE
LV_ERR_CODE_OUT NUMBER;
LV_ERR_MSG_OUT VARCHAR2(2000);
BEGIN
dbms_output.put_line('Your code for data Manipulations');
--Like Insert update or DELETE activities
END;
-- To replace this trigger for emp_v2 table
set serveroutput on;
DECLARE
lv_var LONG;
BEGIN
FOR i IN (
SELECT OWNER,TRIGGER_NAME,DBMS_METADATA.GET_DDL('TRIGGER','EMP_OLD_TRIGGER') ddl_script FROM all_triggers
WHERE OWNER = 'AVROY') LOOP
NULL;
lv_var:=REPLACE(i.ddl_script,'ON EMP FOR EACH ROW','ON EMP_V1 FOR EACH ROW');
dbms_output.put_line(substr(lv_var,1,INSTR(lv_var,'ALTER TRIGGER',1)-1));
EXECUTE IMMEDIATE 'DROP TRIGGER '||I.TRIGGER_NAME;
EXECUTE IMMEDIATE lv_var;
END LOOP;
END;
--Check if DDL manipulation has been done for not
SELECT OWNER,TRIGGER_NAME,DBMS_METADATA.GET_DDL('TRIGGER','EMP_OLD_TRIGGER') ddl_script FROM all_triggers
WHERE OWNER = 'AVROY';
---------------------------------OUTPUT----------------------------------------
"
CREATE OR REPLACE TRIGGER "AVROY"."EMP_OLD_TRIGGER"
AFTER INSERT OR UPDATE ON EMP_V1 FOR EACH ROW
DECLARE
LV_ERR_CODE_OUT NUMBER;
LV_ERR_MSG_OUT VARCHAR2(2000);
BEGIN
dbms_output.put_line('Your code for data Manipulations');
--Like Insert update or DELETE activities
END;
"
-----------------------------OUTPUT----------------------------------------------

Declare Table Variable in Oracle Procedure

I'm having a heck of a time trying to find an example of this being done. I have a procedure, and as part of that procedure I want to store the results of a SELECT statement so that I can work against that set, and then use it as a reference to update the original records when it's all done.
The difficulty I'm having is in declaring the temporary table variable. Here's an example of what I'm trying to do:
PROCEDURE my_procedure
IS
output_text clob;
temp_table IS TABLE OF MY_TABLE%ROWTYPE; -- Error on this line
BEGIN
SELECT * BULK COLLECT INTO temp_table FROM MY_TABLE WHERE SOME_DATE IS NULL;
-- Correlate results into the clob for sending to email (working)
-- Set the SOME_DATE value of the original record set where record is in temp_table
I get an error on the second occurrence of IS, saying that it is an unexpected symbol. This suggests to me that my table variable declaration is either wrong, or in the wrong place. I've tried putting it into a DECLARE block after BEGIN, but I just get another error.
Where should this declaration go? Alternatively, if there is a better solution I'll take that too!
CREATE OR REPLACE PROCEDURE PROCEDURE1 AS
output_text clob;
type temp_table_type IS TABLE OF MY_TABLE%ROWTYPE;
temp_table temp_table_type;
BEGIN
SELECT * BULK COLLECT INTO temp_table FROM MY_TABLE;
END PROCEDURE1;
or
CREATE OR REPLACE PROCEDURE PROCEDURE1 ( output_text OUT clob ) IS
type temp_table_type IS TABLE OF MY_TABLE%ROWTYPE
INDEX BY BINARY_INTEGER;
temp_table temp_table_type;
BEGIN
SELECT * BULK COLLECT INTO temp_table FROM MY_TABLE;
FOR indx IN 1 .. temp_table.COUNT
LOOP
something := temp_table(indx).col_name;
END LOOP;
END PROCEDURE1;
I had a similiar problem and found this:
Selecting Values from Oracle Table Variable / Array?
The global temporary table can be used like a regular table, but its content is only temporary (deleted at end of session/transaction) and each session has its own table content.
If you don't need dynamic SQL this can be used as good solution:
CREATE GLOBAL TEMPORARY TABLE temp_table
(
column1 NUMBER,
column2 NUMBER
)
ON COMMIT DELETE ROWS;
PROCEDURE my_procedure
IS
output_text clob;
BEGIN
-- Clear temporary table for this session (to be sure)
DELETE FROM temp_table;
-- Insert data into temporary table (only for this session)
INSERT INTO temp_table SELECT * FROM MY_TABLE WHERE SOME_DATE IS NULL;
-- ...
END;
The only disadvantages are, in my opinion, that you got another table and that the temporary table is not dynamic.

How to return a table without knowing its structure in advance?

everyone I need to create a function in oracle that accepts a table name and return a collection the content of which is based the table that accepted.
I've been doing some search, many examples are of the form: first, define a table type; then, fill a table of that type and return it.
But I won't know the structure of the collection that need to be returned until the function is called, so I can not define a table type at the time of programming.
How can I make it? Thanks:-)
What I want to do is this:
Say, I have three tables--TABLE_A, TABLE_B, TABLE_C--each of which has different columns. Now I need to create a function func(table_name) that accept the table name(TABLE_A, TABLE_B, or TABLE_C) and return a collection the content of which is determined by the table name passed to the function. As the three tables have different columns, I can't create a type like "TColumnData " which you created. So, how should write the function?
One approach is to use global temporary tables.
create or replace
procedure test_procedure(table_name varchar2) as
begin
declare
table_or_view_not_exist exception;
pragma exception_init(table_or_view_not_exist, -942);
begin
begin
EXECUTE IMMEDIATE 'truncate TABLE TEMP_TABLE';
EXECUTE IMMEDIATE 'DROP TABLE TEMP_TABLE';
exception when table_or_view_not_exist then
DBMS_OUTPUT.PUT_LINE('Table TEMP_TABLE not found. skipping drop..');
end;
EXECUTE IMMEDIATE
'CREATE GLOBAL TEMPORARY TABLE TEMP_TABLE ON COMMIT PRESERVE ROWS AS
SELECT * FROM ' || table_name || ' ';
end;
end test_procedure;
then run the procedure:
execute test_procedure('TABLE_A');
once the procedure has completed execution, you can verify by:
select * from temp_table;

Resources