Oracle:如果表存在

我正在为Oracle数据库编写一些迁移脚本,希望Oracle有类似于MySQL的IF EXISTS构造的东西。

具体来说,每当我想在MySQL中删除一个表时,我都会这样做

 DROP TABLE IF EXISTS `table_name`; 

这样,如果该表不存在,则DROP不会产生错误,并且该脚本可以继续。

Oracle有类似的机制吗? 我意识到我可以使用下面的查询来检查表是否存在

 SELECT * FROM dba_tables where table_name = 'table_name'; 

但与DROP捆绑在一起的语法正在逃避我。

最好和最有效的方法是捕捉“找不到表”exception:这样可以避免检查表是否存在两次; 并且不会遇到这样的问题:如果DROP由于某种其他原因而失败(这可能是重要的),那么exception仍然引发给调用者:

 BEGIN EXECUTE IMMEDIATE 'DROP TABLE mytable'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -942 THEN RAISE; END IF; END; 

附录为了便于参考,以下是其他对象types的等效块:

序列

 BEGIN EXECUTE IMMEDIATE 'DROP SEQUENCE ' || sequence_name; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -2289 THEN RAISE; END IF; END; 

视图

 BEGIN EXECUTE IMMEDIATE 'DROP VIEW ' || view_name; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -942 THEN RAISE; END IF; END; 

触发

 BEGIN EXECUTE IMMEDIATE 'DROP TRIGGER ' || trigger_name; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -4080 THEN RAISE; END IF; END; 

指数

 BEGIN EXECUTE IMMEDIATE 'DROP INDEX ' || index_name; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -1418 THEN RAISE; END IF; END; 

 BEGIN EXECUTE IMMEDIATE 'ALTER TABLE ' || table_name || ' DROP COLUMN ' || column_name; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -904 THEN RAISE; END IF; END; 

数据库链接

 BEGIN EXECUTE IMMEDIATE 'DROP DATABASE LINK ' || dblink_name; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -2024 THEN RAISE; END IF; END; 

物化视图

 BEGIN EXECUTE IMMEDIATE 'DROP MATERIALIZED VIEW ' || mview_name; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -12003 THEN RAISE; END IF; END; 

types

 BEGIN EXECUTE IMMEDIATE 'DROP TYPE ' || type_name; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -4043 THEN RAISE; END IF; END; 

约束

 BEGIN EXECUTE IMMEDIATE 'ALTER TABLE ' || table_name || ' DROP CONSTRAINT ' || constraint_name; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -2443 THEN RAISE; END IF; END; 

调度程序作业

 BEGIN DBMS_SCHEDULER.drop_job(job_name); EXCEPTION WHEN OTHERS THEN IF SQLCODE != -27475 THEN RAISE; END IF; END; 

用户/架构

 BEGIN EXECUTE IMMEDIATE 'DROP USER ' || user_name; /* you may or may not want to add CASCADE */ EXCEPTION WHEN OTHERS THEN IF SQLCODE != -1918 THEN RAISE; END IF; END; 

 BEGIN EXECUTE IMMEDIATE 'DROP PACKAGE ' || package_name; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -4043 THEN RAISE; END IF; END; 

程序

 BEGIN EXECUTE IMMEDIATE 'DROP PROCEDURE ' || procedure_name; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -4043 THEN RAISE; END IF; END; 

function

 BEGIN EXECUTE IMMEDIATE 'DROP FUNCTION ' || function_name; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -4043 THEN RAISE; END IF; END; 

表空间

 BEGIN EXECUTE IMMEDIATE 'DROP TABLESPACE' || tablespace_name; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -959 THEN RAISE; END IF; END; 
 declare c int; begin select count(*) into c from user_tables where table_name = upper('table_name'); if c = 1 then execute immediate 'drop table table_name'; end if; end; 

这是为了检查当前模式中的表是否存在。 为了检查给定的表是否已经存在于不同的模式中,您必须使用all_tables而不是user_tables并添加条件all_tables.owner = upper('schema_name')

我一直在寻找相同的,但我最终写了一个程序来帮助我:

 CREATE OR REPLACE PROCEDURE DelObject(ObjName varchar2,ObjType varchar2) IS v_counter number := 0; begin if ObjType = 'TABLE' then select count(*) into v_counter from user_tables where table_name = upper(ObjName); if v_counter > 0 then execute immediate 'drop table ' || ObjName || ' cascade constraints'; end if; end if; if ObjType = 'PROCEDURE' then select count(*) into v_counter from User_Objects where object_type = 'PROCEDURE' and OBJECT_NAME = upper(ObjName); if v_counter > 0 then execute immediate 'DROP PROCEDURE ' || ObjName; end if; end if; if ObjType = 'FUNCTION' then select count(*) into v_counter from User_Objects where object_type = 'FUNCTION' and OBJECT_NAME = upper(ObjName); if v_counter > 0 then execute immediate 'DROP FUNCTION ' || ObjName; end if; end if; if ObjType = 'TRIGGER' then select count(*) into v_counter from User_Triggers where TRIGGER_NAME = upper(ObjName); if v_counter > 0 then execute immediate 'DROP TRIGGER ' || ObjName; end if; end if; if ObjType = 'VIEW' then select count(*) into v_counter from User_Views where VIEW_NAME = upper(ObjName); if v_counter > 0 then execute immediate 'DROP VIEW ' || ObjName; end if; end if; if ObjType = 'SEQUENCE' then select count(*) into v_counter from user_sequences where sequence_name = upper(ObjName); if v_counter > 0 then execute immediate 'DROP SEQUENCE ' || ObjName; end if; end if; end; 

希望这可以帮助

只是想发布一个完整的代码,将创build一个表,并放弃,如果它已经存在使用杰弗里的代码(荣誉给他,而不是我!)。

 BEGIN BEGIN EXECUTE IMMEDIATE 'DROP TABLE tablename'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -942 THEN RAISE; END IF; END; EXECUTE IMMEDIATE 'CREATE TABLE tablename AS SELECT * FROM sourcetable WHERE 1=0'; END; 

使用SQL * PLUS,您也可以使用WHENEVER SQLERROR命令:

 WHENEVER SQLERROR CONTINUE NONE DROP TABLE TABLE_NAME; WHENEVER SQLERROR EXIT SQL.SQLCODE DROP TABLE TABLE_NAME; 

使用CONTINUE NONE报告错误,但脚本将继续。 使用EXIT SQL.SQLCODE ,脚本将在出现错误时终止。

另请参阅: WHENEVER SQLERROR文档

在oracle中没有“DROP TABLE IF EXISTS”,你必须做select语句。

试试这个(我不是在oracle语法,所以如果我的variablesify,请原谅我):

 declare @count int select @count=count(*) from all_tables where table_name='Table_name'; if @count>0 BEGIN DROP TABLE tableName; END 

你总是可以自己捕捉错误。

 begin execute immediate 'drop table mytable'; exception when others then null; end; 

过度使用这种做法被认为是不好的做法,类似于其他语言中的空白catch()。

问候
ķ

另一种方法是定义一个exception,然后只捕获exception让其他所有的exception传播。

 Declare eTableDoesNotExist Exception; PRAGMA EXCEPTION_INIT(eTableDoesNotExist, -942); Begin EXECUTE IMMEDIATE ('DROP TABLE myschema.mytable'); Exception When eTableDoesNotExist Then DBMS_Output.Put_Line('Table already does not exist.'); End; 
 BEGIN EXECUTE IMMEDIATE 'DROP TABLE "IMS"."MAX" '; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -942 THEN RAISE; END IF; EXECUTE IMMEDIATE ' CREATE TABLE "IMS"."MAX" ( "ID" NUMBER NOT NULL ENABLE, "NAME" VARCHAR2(20 BYTE), CONSTRAINT "MAX_PK" PRIMARY KEY ("ID") USING INDEX PCTFREE 10 INITRANS 2 MAXTRANS 255 STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT) TABLESPACE "SYSAUX" ENABLE ) SEGMENT CREATION IMMEDIATE PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 NOCOMPRESS LOGGING STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT) TABLESPACE "SYSAUX" '; END; 

//执行此代码,检查表是否存在,并在稍后创build表max。 这只是单一编译工作

可悲的是,没有这样的东西,如果存在,或创build如果不存在

你可以编写一个plsql脚本来包含那里的逻辑。

http://download.oracle.com/docs/cd/B12037_01/server.101/b10759/statements_9003.htm

我没有太多的Oracle语法,但我认为@ Erich的脚本会是这样的。

 declare cant integer begin select into cant count(*) from dba_tables where table_name='Table_name'; if count>0 then BEGIN DROP TABLE tableName; END IF; END; 

我更喜欢指定表和架构所有者。

注意区分大小写。 (参见下面的“上”条款)。

我扔了几个不同的对象,以显示可以在TABLE之外的地方使用。

………….

 declare v_counter int; begin select count(*) into v_counter from dba_users where upper(username)=upper('UserSchema01'); if v_counter > 0 then execute immediate 'DROP USER UserSchema01 CASCADE'; end if; end; / CREATE USER UserSchema01 IDENTIFIED BY pa$$word DEFAULT TABLESPACE users TEMPORARY TABLESPACE temp QUOTA UNLIMITED ON users; grant create session to UserSchema01; 

和一个TABLE例子:

 declare v_counter int; begin select count(*) into v_counter from all_tables where upper(TABLE_NAME)=upper('ORDERS') and upper(OWNER)=upper('UserSchema01'); if v_counter > 0 then execute immediate 'DROP TABLE UserSchema01.ORDERS'; end if; end; /