Reputation: 1094
Trying to check is table exist before create in Oracle. Search for most of the post from Stackoverflow and others too. Find some query but it didn't work for me.
IF((SELECT count(*) FROM dba_tables where table_name = 'EMPLOYEE') <= 0)
THEN
create table EMPLOYEE
(
ID NUMBER(3),
NAME VARCHAR2(30) NOT NULL
)
END IF;
Which gives me error
Error: ORA-00900: invalid SQL statement
SQLState: 42000
ErrorCode: 900
Position: 1
I search for the syntax for IF
condition, I think which is also write.
Please suggest me....
Upvotes: 42
Views: 177921
Reputation: 485
For an existing table's i needed this kind of solution and after some gathering,
i did this kind of way: check existence of tables and sequences from SYS.ALL_OBJECTS
and add if necessary(i assumed connected user has/has to access to this)
DECLARE
table_exists NUMBER;
sequence_exists NUMBER;
createTableSql clob;
createSequenceSql clob;
BEGIN
createTableSql:='
CREATE TABLE myTable(....)
';
createSequenceSql := '
CREATE SEQUENCE .....
';
SELECT COUNT(*)
INTO table_exists
FROM SYS.ALL_OBJECTS O
WHERE O.OWNER = 'My_Schema' -- your schema name, i needed it
AND O.OBJECT_TYPE = 'TABLE'
AND O.OBJECT_NAME = 'MyTable'; -- your table name
SELECT COUNT(*)
INTO sequence_exists
FROM SYS.ALL_OBJECTS O
WHERE O.OWNER = 'My_Schema' -- your schema name, i needed it
AND O.OBJECT_TYPE = 'SEQUENCE'
AND O.OBJECT_NAME = 'My_SchemaName'; -- your sequence name
IF
table_exists = 0 THEN
DBMS_OUTPUT.PUT_LINE('table not found(object count: '||table_exists||') adding new...');
execute immediate createTableSql;
ELSE
DBMS_OUTPUT.PUT_LINE('table found(object count:'|| table_exists||') skipping...' );
END IF;
IF
sequence_exists = 0 THEN
DBMS_OUTPUT.PUT_LINE('sequence not found(object count: '||sequence_exists ||') adding new...');
execute immediate createSequenceSql ;
ELSE
DBMS_OUTPUT.PUT_LINE('sequence found(object count:'|| sequence_exists ||') skipping...' );
END IF;
END;
Be careful when creating scripts inside variables, problems occured when i
Have a nice day!
Upvotes: 0
Reputation: 579
As Rene also commented, it's quite uncommon to check first and then create the table. If you want to have a running code according to your method, this will be:
declare
nCount number;
v_sql clob;
begin
select count(*) into nCount from dba_tables where table_name = 'EMPLOYEE';
if ncount <= 0 then
v_sql := '
create table employee
(
id number,
name varchar2(30) not null
)';
execute immediate v_sql;
end if;
end;
/
But I'd rather go catch on the Exception, saves you some unnecessary lines of code:
declare
v_sql clob;
begin
v_sql := '
create table employee
(
id number,
name varchar2(30) not null
)';
execute immediate v_sql;
exception
when others then
if sqlcode = -955 then
null; -- suppresses ora-00955 exception
else
raise;
end if;
end;
/
Since Oracle 23c, you can use the simpler IF NOT EXISTS
syntax:
create table if not exists employee
(
id number,
name varchar2(30) not null
);
Upvotes: 53
Reputation: 29
Its no need declare and count apply too.
begin
for rec in (select 1 from user_tables where table_name = 'YOUR_TABLE')
-- or
-- for rec in (select 1 from all_tables where table_name = 'YOUR_TABLE' and owner = 'YOU')
loop
execute immediate 'create table your_table as (f1 char(1))';
end loop;
end;
/
Will be good mode create check function
create or replace function this_object_exists (p_obj_name user_objects.object_name%type) return boolean
is
begin
for rec in (select 1 from user_objects where object_name = upper(p_obj_name))
loop
return true;
end loop;
return false;
end this_object_exists;
And thus use code for check exists
. | . | . | . |
---|---|---|---|
INDEX PARTITION | TABLE SUBPARTITION | SEQUENCE | TABLE PARTITION |
PROCEDURE | LOB PARTITION | LOB | INDEX SUBPARTITION |
PACKAGE | PACKAGE BODY | TYPE BODY | TRIGGER |
INDEX | TABLE | VIEW | FUNCTION |
SYNONYM | TYPE | JOB | ... |
begin
if not this_object_exists('your_table') then
execute immediate 'create table your_table as (f1 char(1))';
end if;
end;
or
begin
if this_object_exists('your_table') then
execute immediate 'drop table your_table';
end if;
execute immediate 'create table your_table as (f1 char(1))';
end;
Upvotes: 0
Reputation: 2846
Well there are lot of answeres already provided and lot are making sense too.
Some mentioned it is just warning and some giving a temp way to disable warnings. All that will work but add risk when number of transactions in your DB is high.
I came across similar situation today and here is very simple query I came up with...
declare
begin
execute immediate '
create table "TBL" ("ID" number not null)';
exception when others then
if SQLCODE = -955 then null; else raise; end if;
end;
/
955 is failure code.
This is simple, if exception come while running query it will be suppressed. and you can use same for SQL
or Oracle
.
Upvotes: 0
Reputation: 854
My solution is just compilation of best ideas in thread, with a little improvement. I use both dedicated procedure (@Tomasz Borowiec) to facilitate reuse, and exception handling (@Tobias Twardon) to reduce code and to get rid of redundant table name in procedure.
DECLARE
PROCEDURE create_table_if_doesnt_exist(
p_create_table_query VARCHAR2
) IS
BEGIN
EXECUTE IMMEDIATE p_create_table_query;
EXCEPTION
WHEN OTHERS THEN
-- suppresses "name is already being used" exception
IF SQLCODE = -955 THEN
NULL;
END IF;
END;
BEGIN
create_table_if_doesnt_exist('
CREATE TABLE "MY_TABLE" (
"ID" NUMBER(19) NOT NULL PRIMARY KEY,
"TEXT" VARCHAR2(4000),
"MOD_TIME" TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
');
END;
/
Upvotes: 2
Reputation: 37
-- checks for table in specfic schema:
declare n number(10);
begin
Select count(*) into n from SYS.All_All_Tables where owner = 'MYSCHEMA' and TABLE_NAME = 'EMPLOYEE';
if (n = 0) then
execute immediate
'create table MYSCHEMA.EMPLOYEE ( ID NUMBER(3), NAME VARCHAR2(30) NOT NULL)';
end if;
end;
Upvotes: 0
Reputation: 1515
Any solution which relies on testing before creation can run into a 'race' condition where another process creates the table between you testing that it does not exists and creating it. - Minor point I know.
Upvotes: 3
Reputation: 91
I know this topic is a bit old, but I think I did something that may be useful for someone, so I'm posting it.
I compiled suggestions from this thread's answers into a procedure:
CREATE OR REPLACE PROCEDURE create_table_if_doesnt_exist(
p_table_name VARCHAR2,
create_table_query VARCHAR2
) AUTHID CURRENT_USER IS
n NUMBER;
BEGIN
SELECT COUNT(*) INTO n FROM user_tables WHERE table_name = UPPER(p_table_name);
IF (n = 0) THEN
EXECUTE IMMEDIATE create_table_query;
END IF;
END;
You can then use it in a following way:
call create_table_if_doesnt_exist('my_table', 'CREATE TABLE my_table (
id NUMBER(19) NOT NULL PRIMARY KEY,
text VARCHAR2(4000),
modified_time TIMESTAMP
)'
);
I know that it's kinda redundant to pass table name twice, but I think that's the easiest here.
Hope somebody finds above useful :-).
Upvotes: 9
Reputation: 19
declare n number(10);
begin
select count(*) into n from tab where tname='TEST';
if (n = 0) then
execute immediate
'create table TEST ( ID NUMBER(3), NAME VARCHAR2 (30) NOT NULL)';
end if;
end;
Upvotes: 1
Reputation: 18659
Please try:
SET SERVEROUTPUT ON
DECLARE
v_emp int:=0;
BEGIN
SELECT count(*) into v_emp FROM dba_tables where table_name = 'EMPLOYEE';
if v_emp<=0 then
EXECUTE IMMEDIATE 'create table EMPLOYEE ( ID NUMBER(3), NAME VARCHAR2(30) NOT NULL)';
end if;
END;
Upvotes: 1