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 结合在一起的语法却让我无法理解。
I'm writing some migration scripts for an Oracle database, and was hoping Oracle had something similar to MySQL's IF EXISTS
construct.
Specifically, whenever I want to drop a table in MySQL, I do something like
DROP TABLE IF EXISTS `table_name`;
This way, if the table doesn't exist, the DROP
doesn't produce an error, and the script can continue.
Does Oracle have a similar mechanism? I realize I could use the following query to check if a table exists or not
SELECT * FROM dba_tables where table_name = 'table_name';
but the syntax for tying that together with a DROP
is escaping me.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(16)
最好、最有效的方法是捕获“未找到表”异常:这可以避免两次检查表是否存在的开销;并且不会遇到这样的问题:如果 DROP 由于某些其他原因(可能很重要)失败,仍然会向调用者引发异常:
23c 语法 由于 版本 23c,Oracle 支持更简单的
IF EXISTS< /code> 所有 drop DDL 的语法:
ADDENDUM
作为参考,以下是其他对象类型的等效块:
序列
视图
触发器
索引
列
数据库链接
物化视图
类型
约束
调度程序 作业
用户/模式
包 过程
函数
表
空间
同义词
The best and most efficient way is to catch the "table not found" exception: this avoids the overhead of checking if the table exists twice; and doesn't suffer from the problem that if the DROP fails for some other reason (that might be important) the exception is still raised to the caller:
23c syntax Since version 23c, Oracle supports a simpler
IF EXISTS
syntax for all drop DDL:ADDENDUM
For reference, here are the equivalent blocks for other object types:
Sequence
View
Trigger
Index
Column
Database Link
Materialized View
Type
Constraint
Scheduler Job
User / Schema
Package
Procedure
Function
Tablespace
Synonym
这是为了检查当前模式中的表是否存在。
要检查给定表是否已存在于不同的架构中,您必须使用
all_tables
而不是user_tables
并添加条件all_tables.owner = upper( 'schema_name')
That's for checking whether a table in the current schema exists.
For checking whether a given table already exists in a different schema, you'd have to use
all_tables
instead ofuser_tables
and add the conditionall_tables.owner = upper('schema_name')
我一直在寻找相同的东西,但最终我写了一个程序来帮助我:
希望这有帮助
I have been looking for the same but I ended up writing a procedure to help me out:
Hope this helps
只是想发布一个完整的代码,该代码将使用 Jeffrey 的代码创建一个表并删除它(如果它已经存在)(向他致敬,而不是我!)。
just wanted to post a full code that will create a table and drop it if it already exists using Jeffrey's code (kudos to him, not me!).
对于 SQL*PLUS,您还可以使用 WHENEVER SQLERROR 命令:
使用
CONTINUE NONE
会报告错误,但脚本将继续。使用EXIT SQL.SQLCODE
,脚本将在出现错误时终止。另请参阅:WHENEVER SQLERROR 文档
With SQL*PLUS you can also use the WHENEVER SQLERROR command:
With
CONTINUE NONE
an error is reported, but the script will continue. WithEXIT SQL.SQLCODE
the script will be terminated in the case of an error.see also: WHENEVER SQLERROR Docs
另一种方法是定义一个异常,然后只捕获该异常,让所有其他异常传播。
Another method is to define an exception and then only catch that exception letting all others propagate.
我更喜欢以下经济解决方案
I prefer following economic solution
一种方法是使用 DBMS_ASSERT.SQL_OBJECT_NAME :
DBFiddle 演示
One way is to use DBMS_ASSERT.SQL_OBJECT_NAME :
DBFiddle Demo
Oracle 中没有“DROP TABLE IF EXISTS”,您必须执行 select 语句。
试试这个(我不熟悉oracle语法,所以如果我的变量是ify,请原谅我):
There is no 'DROP TABLE IF EXISTS' in oracle, you would have to do the select statement.
try this (i'm not up on oracle syntax, so if my variables are ify, please forgive me):
如果您想让它可重新输入并最大程度地减少删除/创建周期,您可以使用 dbms_metadata.get_ddl 缓存 DDL,并使用如下结构重新创建所有内容:
<代码>
宣布
v_ddl varchar2(4000);
开始
从 Dual 选择 dbms_metadata.get_ddl('TABLE','DEPT','SCOTT') 到 v_ddl 中;
[比较缓存的 DDL,如果不匹配则执行]
当其他人那么时例外
如果 sqlcode = -31603 那么
[获取并执行缓存的 DDL]
别的
增加;
结束如果;
结尾;
这只是一个示例,内部应该有一个循环,其中 DDL 类型、名称和所有者是变量。
And if you want to make it re-enterable and minimize drop/create cycles, you could cache the DDL using dbms_metadata.get_ddl and re-create everything using a construct like this:
declare
v_ddl varchar2(4000);
begin
select dbms_metadata.get_ddl('TABLE','DEPT','SCOTT') into v_ddl from dual;
[COMPARE CACHED DDL AND EXECUTE IF NO MATCH]
exception when others then
if sqlcode = -31603 then
[GET AND EXECUTE CACHED DDL]
else
raise;
end if;
end;
This is just a sample, there should be a loop inside with DDL type, name and owner being variables.
像这样的块可能对您有用。
A block like this could be useful to you.
以下片段对我有用
The following snippet worked for me
您总是可以自己发现错误。
过度使用它被认为是不好的做法,类似于其他语言中的空 catch()。
问候
K
You could always catch the error yourself.
It is considered bad practice to overuse this, similar to empty catch()'es in other languages.
Regards
K
遗憾的是,不存在,不存在诸如 drop ifexists 或 CREATE IF NOT EXIST 之类的东西。
您可以编写一个 plsql 脚本来包含其中的逻辑。
http://download.oracle.com/docs/ cd/B12037_01/server.101/b10759/statements_9003.htm
我不太了解 Oracle 语法,但我认为 @Erich 的脚本会是这样的。
Sadly no, there is no such thing as drop if exists, or CREATE IF NOT EXIST
You could write a plsql script to include the logic there.
http://download.oracle.com/docs/cd/B12037_01/server.101/b10759/statements_9003.htm
I'm not much into Oracle Syntax, but i think @Erich's script would be something like this.
我更喜欢指定表和架构所有者。
还要注意区分大小写。 (参见下面的“上”条款)。
我放入了几个不同的对象来表明它可以在表格之外的地方使用。
............
还有一个表格示例:
I prefer to specify the table and the schema owner.
Watch out for case sensitivity as well. (see "upper" clause below).
I threw a couple of different objects in to show that is can be used in places besides TABLEs.
.............
And a TABLE example:
// 执行此代码,检查表是否存在,然后创建表 max。这仅适用于单一编译
// Doing this code, checks if the table exists and later it creates the table max. this simply works in single compilation