Oracle - determining whether a table exists - oracle

How do you determine in oracle whether a table exists?
On a script file, I wanted to delete a table only if it exists.
Thanks!

http://www.dba-oracle.com/bk_check_table_exists.htm
There are various solutions given here. The simplest ones:
SQL> desc mytable
Or just try to drop and catch the exception:
begin
execute immediate 'drop table TABLE1';
exception when others then null;
end;

Oracle has an all_tables table, you could query that to see.
Maybe something like this:
declare
v_tab_count number := 0;
begin
select count(*)
into v_tab_count
from all_tables
where table_name = 'MY_TABLE';
if v_tab_count > 0 then
execute immediate 'drop table my_table';
else
dbms_output.put_line('The table isn''t there! maybe you deleted it already?');
end if;
exception
when others then
dbms_output.put_line( sqlerrm);
end if;
/
I know I commented earlier on someone else's post that I didn't like using execute immediate for this, but I'd forgotten that it's the only way to perform a drop table from PL/SQL.

You can query USER_TABLES for TABLE_NAME = 'YOUR_TABLE_NAME' :-)

Related

Detecting a Deadlock in a Stored Procedure

I am trying to write a deadlock proof stored procedure. It is based on the following concept.
I have been trying to write a stored procedure which is based on the following concept. The procedure will try to drop a constraint on a table and if in case it detects a deadlock situation, it wait for some time before trying again. The important thing is it should only retry in case of a Deadlock or a NOWAIT error, all other errors are to be handled via exceptions.
Procedure test
is
BEGIN
<<label>>
DROP constraint on a table
if (deadlock(ORA-00060)/Nowait Error (ORA-0054)) detected
then
sleep for 60 seconds
Goto label
exception
when others.
It would be great if any of the experts please help me with this. A similar example would be highly helpful. Thank you for your help.
While some people harbour an irrational aversion to goto it remains true that usually we can implement the same logic without using the construct. That is true here: a simple while loop is all that is necessary:
create or replace procedure drop_constraint_for_sure
( p_table_name in varchar2
, p_constraint_name in varchar2
)
is
x_deadlock exception;
pragma exception_init(x_deadlock, -60);
x_nowait exception;
pragma exception_init(x_nowait, -54);
begin
loop
begin
execute immediate 'alter table '|| p_table_name
|| ' drop constraint ' || p_constraint_name
|| ' cascade' ;
exit;
exception
when x_deadlock then null;
when x_nowait then null;
end;
dbms_lock.sleep(60);
end loop;
end;
/
Note that the sleep function requires the execute privilege on SYS.DBMS_LOCK. This is not granted by default, so if you don't have it you'll need to ask your friendly DBA to grant it.
Also note that this implementation doesn't have any form of abort. So it will loop eternally, until the constraint is dropped or some other exception occurs. In real life you should include a loop count with an additional exit test on a threshold for the count. Although in real life I probably wouldn't want a stored procedure like this anyway: I prefer knowing as soon as possible when someone is using a table I'm trying to alter.
Hope below snippet gives you can an idea to achieve your requirement.
CREATE OR REPLACE
PROCEDURE DRP_CONST_DEALDOCK
AS
DEADLOCK_EX EXCEPTION;
NO_WAIT_EX EXCEPTION;
PRAGMA EXCEPTION_INIT(DEADLOCK_EX,-60);
PRAGMA EXCEPTION_INIT(NO_WAIT_EX, -54);
lv_cnt PLS_INTEGER;
BEGIN
BEGIN
EXECUTE IMMEDIATE 'ALTER TABLE STACK_OF_TEST DROP CONSTRAINT SYS_C00375020';
EXCEPTION
WHEN DEADLOCK_EX THEN
dbms_output.put_line('nowait exception');
DBMS_LOCK.SLEEP(10);
SELECT COUNT(1)
INTO lv_cnt
FROM v$locked_object
WHERE object_id IN
(SELECT OBJECT_ID FROM DBA_OBJECTS WHERE OBJECT_NAME = 'STACK_OF_TEST'
);
WHILE lv_cnt > 0
LOOP
dbms_lock.sleep(10);
SELECT COUNT(1)
INTO lv_cnt
FROM v$locked_object
WHERE object_id IN
(SELECT OBJECT_ID FROM DBA_OBJECTS WHERE OBJECT_NAME = 'STACK_OF_TEST'
);
END LOOP;
WHEN NO_WAIT_EX THEN
dbms_output.put_line('nowait exception');
DBMS_LOCK.SLEEP(10);
SELECT COUNT(1)
INTO lv_cnt
FROM v$locked_object
WHERE object_id IN
(SELECT OBJECT_ID FROM DBA_OBJECTS WHERE OBJECT_NAME = 'STACK_OF_TEST'
);
WHILE lv_cnt > 0
LOOP
dbms_lock.sleep(10);
SELECT COUNT(1)
INTO lv_cnt
FROM v$locked_object
WHERE object_id IN
(SELECT OBJECT_ID FROM DBA_OBJECTS WHERE OBJECT_NAME = 'STACK_OF_TEST'
);
END LOOP;
WHEN OTHERS THEN
dbms_output.put_line(SQLCODE||'-->'||SQLERRM);
END;
END;

How to check in Oracle if table is read only?

I would like to make an ORACLE table read only. It is possible using:
ALTER TABLE table1 READ ONLY;
However when table1 is already read only, then altering table is causing error.
So the question is how to check if table1 is read only, and if it isn't then
then to make it read only.
Check user_tables:
select read_only
from user_tables
where table_name = 'TABLE1'
You may use dynamic SQL to execute the ALTER only if necessary, avoiding errors if the table already is read-only:
DECLARE
vCheck VARCHAR2 (3);
BEGIN
BEGIN
SELECT read_only
INTO vCheck
FROM user_tables
WHERE table_name = 'TABLE1';
EXCEPTION
WHEN NO_DATA_FOUND
THEN
vCheck := 'YES'; -- Avoid ALTER in case of TABLE1 not existing
END;
--
IF vCheck = 'NO'
THEN
EXECUTE IMMEDIATE 'ALTER TABLE TABLE1 READ ONLY';
END IF;
END;

Are there any alternative to cursor in Oracle for performance improvements?

I have the below query which truncates specific tables in a specific schema. Is there a better option to do this without cursor? This query takes a a few minutes to execute as the schema is big.
DECLARE TYPE cur_typ IS REF CURSOR;
c cur_typ;
qry_str VARCHAR2(1000);
table_name VARCHAR2(50);
BEGIN
qry_str := \'SELECT TABLE_NAME FROM USER_ALL_TABLES
WHERE (TABLE_NAME like \'\'STG_%\'\'
OR TABLE_NAME like \'\'S_%\'\' )\';
OPEN c FOR qry_str;
LOOP
FETCH c INTO table_name;
EXIT WHEN c%NOTFOUND;
EXECUTE IMMEDIATE \'TRUNCATE TABLE \' || table_name;
END LOOP;
CLOSE c;
Do any of you have any faster alternative?
Thanks for the help.
If there is more than handful of tables, TRUNCATE is the bigger issue than the query. It's DDL, pretty heavy statement.
Have you tried an inline cursor?
BEGIN
FOR row in (
SELECT TABLE_NAME FROM USER_ALL_TABLES
WHERE TABLE_NAME like 'STG_%'
OR TABLE_NAME like 'S_%'
) LOOP
EXECUTE IMMEDIATE 'TRUNCATE TABLE ' || row.table_name;
END LOOP;
END;
That doesn't get rid of the cursor, just hides it under the covers, but is more readable. If you are seeing performance problems, try tuning the query.
You can use FORALL.
You can also store tables you want to truncate in separate table and do not query dictionary table.

add a specific column to all tables that exist in an oracle database

Is there a way to achieve this? Something like
alter table
'all_tables' add(newcol varchar2(20));
is this possible?
run the following in sqlplus or sql developer, and then run the output from the query
select 'alter table ' || table_name || ' add (newcol varchar2(20));'
from user_tables
Or directly execute the alter statements using execute immediate
begin
for i in (select table_name from user_tables)
loop
execute immediate 'alter table '||i.table_name||' add (newcol varchar2(20))';
end loop;
end;
/

Check if table exists in the database - PL SQL

I'm new in PL SQL, and I need to check if table exist on server and drop it.
Thanks in advance,
Goran
you can query the tablenames
select tname from tab where tname = 'TABLE_NAME_TO_SEARCH_FOR';
select tname from tab where tname = 'TABLE_NAME';
This is where the true power of the information schema comes in.
A simple query will point you in the right direction
SELECT
*
FROM
information_schema.tables
WHERE
table_name='salesorders';
This can then be used in plpg function
CREATE OR REPLACE FUNCTION table_exists(v_table text)
RETURNS boolean AS
$BODY$
DECLARE
v_count int;
v_sql text;
BEGIN
v_sql =
'SELECT ' ||
' count(1) ' ||
'FROM ' ||
' information_schema.tables ' ||
'WHERE ' ||
E' table_name=\'' || v_table || E'\'';
EXECUTE v_sql INTO v_count;
RETURN v_count>0;
END;
$BODY$
LANGUAGE 'plpgsql' VOLATILE
COST 100;
Use the function
select * from table_exists('salesordesrs');
That should be enough to get you going.
OOPS
Seems I misread the original posters question. I've answered for PostgreSQL.
Peter.
The most efficient method is, don't. Just drop the table. If the table didn't exist already, it'll raise an exception.
Running a query just before dropping the table is just wasting time doing what Oracle will do automatically for you.
You can handle the exception however you want, e.g.:
BEGIN
EXECUTE IMMEDIATE 'DROP TABLE "MYTABLE"';
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE = -942 THEN
DBMS_OUTPUT.put_line('the table did not exist!');
ELSE
RAISE;
END IF;
END;
I had some troubles with the solutions above, as my DB has a peculiar tree structure. This should give every table in your schema:
SELECT
table_name
FROM
all_tables
WHERE
table_name = '<your table here>'

Resources