Drop Table Exception Intermittently doesn't work - sql

I have been wrapping my "drop tables" in the following block to avoid raising 942 errors if the table doesn't exist:
BEGIN
EXECUTE IMMEDIATE 'DROP TABLE MY_TABLE1';
EXECUTE IMMEDIATE 'DROP TABLE MY_TABLE2';
EXECUTE IMMEDIATE 'DROP TABLE MY_TABLE3';
EXECUTE IMMEDIATE 'DROP TABLE MY_TABLE4';
EXECUTE IMMEDIATE 'DROP TABLE MY_TABLE5';
EXECUTE IMMEDIATE 'DROP TABLE MY_TABLE6';
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE != -942 THEN RAISE;
END IF;
END;
This works great most of the of time. However, intermittently it will seem to refuse to drop this table or that. It's not always the same table, and it doesn't always happen in any particular set of queries. It just happens...sometimes...for reasons I can't explain, hence my asking this question.
Has anyone else experienced this, and if so, what did you do about it?

Most likely cause I can think of is the table is locked (outstanding commits) in another session. What error is reported?
Also there is a problem with your script - if TABLE1 has already been dropped, TABLE2...6 won't get dropped because your first DROP will jump to the exception.
Better to do this:
DECLARE
PROCEDURE drp ( tName IN VARCHAR2 ) IS
BEGIN
EXECUTE IMMEDIATE 'drop table ' || tName;
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE != -942 THEN RAISE;
END IF;
END;
BEGIN
drp ( 'TABLE1' );
drp ( 'TABLE2' );
drp ( 'TABLE3' );
-- etc
END;

Related

multiple drop trigger statements not working

The below PL/SQL is not working as expected
The ask is to delete triggers if it exists. The below is deleting only the first trigger.
BEGIN
EXECUTE IMMEDIATE 'DROP TRIGGER ' || 'trigger1';
EXECUTE IMMEDIATE 'DROP TRIGGER ' || 'trigger2';
EXECUTE IMMEDIATE 'DROP TRIGGER ' || 'trigger3';
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE != -4080 THEN
RAISE;
END IF;
END;
If the first or second trigger doesn't exist then you'll drop to the exception handler. It won't then return to the original program flow, even when you ignore the error, and it will never see or attempt the later dynamic calls.
You need an exception handler around each individual drop.
To reduce repetition you could do that in a loop, or with a local procedure:
DECLARE
PROCEDURE drop_trigger(p_trigger_name user_triggers.trigger_name%type) IS
BEGIN
EXECUTE IMMEDIATE 'DROP TRIGGER ' || p_trigger_name;
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE != -4080 THEN
RAISE;
END IF;
END drop_trigger;
BEGIN
drop_trigger('trigger1');
drop_trigger('trigger2');
drop_trigger('trigger3');
END;
/
db<>fiddle
You can also add debugging, with dbms_output, to see what's happening - as in this modified db<>fiddle.

Delete rows only if the table exists

I need to run a delete statement on my database if a table was previously created.
The problem is - I can't just run the delete statement, since the product is not on every client's productive environments - therefore, they don't have the table where I want to run the delete statement, and would end up with an error 00942. 00000 - "table or view does not exist".
An example:
I would like to run something like this:
IF EXISTS (TABLE TB_FIELD)
DELETE FROM TB_FIELD WHERE ID = '213';
If there isn't a generic statement, I would like one that would run for Oracle databases
Here's one for Oracle. This assumes the current user owns the table. If you're updating someone else's table you'll need to swap out user_tables with dba_tables.
declare
table_name_l user_tables.table_name%type;
begin
select table_name into table_name_l from user_tables where table_name = 'TB_FIELD';
-- if we didn't raise an exception the table must exist
execute immediate 'delete from tb_field where id = :1' using '213';
exception
when no_data_found then
-- do nothing - table doesn't exist
null;
end;
Simplest way is to catch and ignore the "table not found" exception:
declare
l_id number := 12345;
begin
execute immediate 'delete tb_field where id=:1' using l_id;
exception
when others then
if sqlcode != -942 /*table or view does not exist*/ then
raise;
end if;
end;
/

Drop table having name: <table_name>_(sysdate-1) only if the table exist

I need to drop a table only if the table exist, can do it using plsql block
BEGIN
EXECUTE IMMEDIATE 'DROP TABLE <table_name>;
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE != -942 THEN
RAISE;
END IF;
END
But in my case the table name has sysdate (02062017) eg table001_02072017 and i need to delete all such tables with sysdate-1.
How can i do so?
You can find the table with the given pattern from user_tables dictionary table and loop on the result to drop each one by one.
begin
for t in (select table_name from user_tables
where table_name like '%\_'||to_char(sysdate-1,'mmddyyyy') escape '\')
loop
execute immediate 'drop table ' || t.table_name;
end loop;
exception
/* Handle your exceptions here. */
end;
/
Using WHEN OTHERS in your exception handling is discouraged. You should explicitly handle the errors.
Dynamic sql will help you here just use
execute immediate 'drop table ' || table_name;
inside your procedure

How to create a procedure in an oracle sql script and use it inside the script?

I want to create a script for my oracle DB, which drops tables. If the table does not exist, the script won't exit as fail, just print a text: "does not exists".
The script is the following:
BEGIN
EXECUTE IMMEDIATE 'DROP TABLE mytable';
DBMS_Output.Put_Line(' table dropped');
EXCEPTION WHEN OTHERS THEN
IF SQLCODE = -942 THEN
DBMS_Output.Put_Line(' table not exists');
ELSE
DBMS_Output.Put_Line(' Unknown exception while dropping table');
RAISE;
END IF;
END;
I want to drop a lot of table in one script, and I don't want to write these lines more than once.
Is there any way, to write it to a procedure or function which gets a parameter (the name of the table), and call this procedure in that script?
Maybe something like this:
drop_table_procedure('mytableA');
drop_table_procedure('mytableB');
Or maybe a procedure, which gets an undefined size list (like in java: String ... table names):
drop_tables_procedure('mytableA','mytableB');
Please give me some examples.
Thanks!
Yes, you can declare a "temporary" procedure in an anonymous PL/SQL block:
DECLARE
PROCEDURE drop_if_exists(p_tablename VARCHAR)
IS
BEGIN
EXECUTE IMMEDIATE 'DROP TABLE '||p_tablename;
DBMS_Output.Put_Line(' table dropped');
EXCEPTION WHEN OTHERS THEN
IF SQLCODE = -942 THEN
DBMS_Output.Put_Line(' table not exists');
ELSE
DBMS_Output.Put_Line(' Unknown exception while dropping table');
RAISE;
END IF;
END;
BEGIN
drop_if_exists('TABLE_1');
drop_if_exists('TABLE_2');
END;
/
in execute immediate you need add name of database object.
here's the script
create table t1 (col1 int);
create table t2 (col1 int);
create procedure drop_my_table(av_name varchar2)
as
begin
EXECUTE IMMEDIATE 'DROP TABLE '||av_name;
DBMS_Output.Put_Line(' table dropped');
EXCEPTION WHEN OTHERS THEN
IF SQLCODE = -942 THEN
DBMS_Output.Put_Line(' table not exists');
ELSE
DBMS_Output.Put_Line(' Unknown exception while dropping table');
RAISE;
END IF;
end drop_my_table;
declare
type array_t is varray(2) of varchar2(30);
atbls array_t := array_t('t1', 't2');
begin
for i in 1..atbls.count loop
drop_my_table(atbls(i));
end loop;
end;
You can use below one also
create or replace PROCEDURE drop_if_exists(p_tablename in VARCHAR)
IS
v_var1 number;
begin
select 1 into v_var1 from user_tables where table_name=upper(p_tablename);
if v_var1=1
then
EXECUTE IMMEDIATE 'DROP TABLE '||p_tablename;
DBMS_Output.Put_Line(' table dropped');
else
DBMS_Output.Put_Line(' table not exist');
end if;
exception
when others then
DBMS_Output.Put_Line(' Unknown exception while dropping table');
RAISE;
end;
Call procedure
begin
drop_if_exists('emp');
end;
/

Oracle SQL - If Exists, Drop Table & Create

Can some one please guide me what's wrong with this query? In SQL Server we just check the presence of the Object_ID of a table to drop it and re-create it. I am new to Oracle and wrote this query:
declare Table_exists INTEGER;
BEGIN
Select count(*) into Table_exists from sys.all_tables where table_name='TABLENAME1';
EXCEPTION
WHEN NO_DATA_FOUND
THEN
Table_Exists :=0;
if(table_exists)=1
Then
Execute Immediate 'Drop Table TABLENAME1;'
'Create Table TABLENAME1;';
DBMS_OUTPUT.PUT_LINE('Table Dropped and Re-Created!');
Else
Execute Immediate 'Create Table TABLENAME1;';
DBMS_OUTPUT.PUT_LINE('New Table Created!');
END IF;
END;
I get the output - ANONYMOUS BLOCK COMPLETED, but the table is not created. The table was previously existing, so I dropped it to check if the PL/SQL is actually creating the table, but NO. What is wrong here? What am I missing? Please guide.
When you are using all_tables filter the results for your
schema by adding where owner = 'your_schema'
or use sys.user_tables
ALL_TABLES describes the relational tables accessible to the current user
USER_TABLES describes the relational tables owned by the current user.
When use execute_emmidiate remove the ; from the query;
Modified query;
DECLARE
Table_exists INTEGER;
BEGIN
Select count(*) into Table_exists from sys.user_tables where table_name='TABLENAME1';
--or
--Select count(*) into Table_exists from sys.all_tables
--where table_name='TABLENAME1' and owner = 'your_DB';
if table_exists = 1 Then
Execute Immediate 'Drop Table TABLENAME1';
Execute Immediate 'Create Table TABLENAME1(num number)';
DBMS_OUTPUT.PUT_LINE('Table Dropped and Re-Created!');
Else
Execute Immediate 'Create Table TABLENAME1(num number)';
DBMS_OUTPUT.PUT_LINE('New Table Created!');
END IF;
END;
First note:
Select count(*) into Table_exists
from sys.all_tables
where table_name = 'TABLENAME1';
will always return one row. You don't need the exception handling.
My best guess is that you have more than one table called TABLENAME1. Run this query to find out:
Select *
from sys.all_tables
where table_name = 'TABLENAME1';
Oracle stores tables from all owners that you can access. You might also want to check OWNER_NAME in the where clause.
However, you seem to understand exception handling. So, just drop the table, ignore any errors, and then recreate the table.
The EXCEPTION clause lasts till the next END and not just the next statement. If you want to continue after catching the exception you need to add an additional BEGIN/END:
declare
Table_exists INTEGER;
BEGIN
BEGIN
Select count(*) into Table_exists from sys.all_tables where table_name='TABLENAME1';
EXCEPTION
WHEN NO_DATA_FOUND THEN
Table_Exists :=0;
END;
if(table_exists)=1 Then
Execute Immediate 'Drop Table TABLENAME1;'
Execute Immediate 'Create Table TABLENAME1;';
DBMS_OUTPUT.PUT_LINE('Table Dropped and Re-Created!');
Else
Execute Immediate 'Create Table TABLENAME1;';
DBMS_OUTPUT.PUT_LINE('New Table Created!');
END IF;
END;
As pointed out by Gordon, the EXCEPTION clause is not really needed in this case since count(*) will always return one row. So the following is sufficient:
declare
Table_exists INTEGER;
BEGIN
Select count(*) into Table_exists from sys.all_tables where table_name='TABLENAME1';
if(table_exists)=1 Then
Execute Immediate 'Drop Table TABLENAME1;'
Execute Immediate 'Create Table TABLENAME1;';
DBMS_OUTPUT.PUT_LINE('Table Dropped and Re-Created!');
Else
Execute Immediate 'Create Table TABLENAME1;';
DBMS_OUTPUT.PUT_LINE('New Table Created!');
END IF;
END;