如果表存在,则删除该表并重新创建,如果不存在,则只需创建。

214

我被难住了,不知道如何开始处理这个问题。

基本上,我只想创建一个表,但如果它已经存在,则需要删除并重新创建它,而不是仅截断它;但如果它不存在,则只需创建它。

有没有人能帮忙?


@Shomz,这就是他们想要的。然而,这个问题的存在和这个页面的20k浏览量证明了这几乎像将英语转换成希腊语一样困难。 - Pacerier
2
@Pacerier 完全同意:删除数组,如果它存在的话 - Shomz
@Shomz,这里有一个语法错误。 - Pacerier
4个回答

395

CREATE TABLE语句之前只需加上DROP TABLE IF EXISTS `tablename`;语句。

该语句会删除表格(如果存在),但如果不存在,不会引发错误。


2
谢谢!这也适用于表或视图列表!DROP TABLE IF EXISTS 'table1','table2';DROP VIEW IF EXISTS 'view1','view2'; PS-你使用了什么巫术在内联代码中有 `s!? - Campbeln
2
@Campbeln 只需在代码段前后加上两个反引号即可。单个反引号将按原样显示。 - r3mainer

59

只需使用 DROP TABLE IF EXISTS 即可:

DROP TABLE IF EXISTS `foo`;
CREATE TABLE `foo` ( ... );

如果您有其他问题,请先尝试搜索MySQL文档


22

嗯...哎呀。多年来没有人提及一个微妙的事情。

尽管DROP TABLE IF EXISTS `bla`; CREATE TABLE `bla` ( ... );看起来合理,但这会导致这样一种情况:旧表已经不存在了,而新表还没有被创建:某些客户端可能会在此时尝试访问该表。

更好的方法是创建全新的表格并将其与旧表格交换(表格内容会丢失):

CREATE TABLE `bla__new` (id int); /* if not ok: terminate, report error */
RENAME TABLE `bla__new` to `bla`; /* if ok: terminate, report success */
RENAME TABLE `bla` to `bla__old`, `bla__new` to `bla`;
DROP TABLE IF EXISTS `bla__old`;
  • 执行CREATE ...操作后应该检查结果,如果出现错误则不继续进行操作。失败意味着其他线程尚未完成同一脚本,可能是由于在中途崩溃或尚未完成。最好自己检查一下。
  • 然后,应该检查第一个RENAME ...的结果,在成功的情况下不要继续进行:整个操作已经成功完成;更重要的是,如果另一个线程已经开始了相同的序列,运行下一个RENAME ...可能会导致不安全(最好考虑这种情况而不是不考虑,参见下面的锁定说明)。
  • 第二个RENAME ...原子性地替换了表定义,请参阅MySQL手册以获取详情。
  • 最后,DROP ...只是清除旧表。

将所有语句用类似SELECT GET_LOCK('__upgrade', -1); ... DO RELEASE_LOCK('__upgrade');包装起来,可以顺序调用所有语句而无需检查错误,但我认为这不是一个好主意:复杂度增加,并且MySQL中的锁定函数对基于语句的复制不安全。

如果表数据应该保留在表定义升级后... 对于一般情况,这是一个更加复杂的故事,涉及比较表定义以查找差异并生成适当的ALTER ...语句,这并不总是可以自动完成,例如在重命名列时。

附注1: 您可以使用相同的方法处理视图,在这种情况下,CREATE/DROP TABLE仅转换为CREATE/DROP VIEW,而RENAME TABLE保持不变。实际上,您甚至可以将表转换为视图,反之亦然。

CREATE VIEW `foo__new` as ...; /* if not ok: terminate, report error */
RENAME TABLE `foo__new` to `foo`; /* if ok: terminate, report success */
RENAME TABLE `foo` to `foo__old`, `foo__new` to `foo`;
DROP VIEW IF EXISTS `foo__old`;

注意2: MariaDB用户应该对CREATE OR REPLACE TABLE/VIEW感到满意,因为它已经关心了主题问题及其细节。


非常好的解决方案!不必在操作进行到一半时进行检查,是否可以先执行“CREATE TABLE IF NOT EXISTS foo(ignore int)”,这样第一个重命名就是不必要的?然后第二个重命名总是有效的,查询结束时当前表或虚拟表将被删除。 - Sebastian Mendez
这种方式看起来很合理,但实际上对于通用情况(假设整个系统不处于“需要恢复”的状态)需要更多的操作才能完成。 - Alex Offshore
使用MariaDB的CREATE OR REPLACE时,请注意它的行为类似于DROP TABLE IF EXISTS foo; CREATE TABLE foo ...,因此如果服务器在DROPCREATE之间崩溃,则表将被删除但不会重新创建,最终你将没有任何表。我建议你使用上面描述的重命名方法,直到CREATE OR REPLACE变成原子性操作 - Adrian Wiik

3

我需要删除一个表并重新创建一个包含来自视图的数据的表。我是通过以下方式创建一个基于视图的表:

DROP TABLE <table_name>;
CREATE TABLE <table_name> AS SELECT * FROM <view>;

我在使用MySQL MariaDb时,上述方法对我有效。


删除表 table_name;创建表并从视图中选择所有内容:create table as select * from the view; - sirskoy
如果您使用的是MariaDB(MySQL缺少此功能),那么您可以简单地使用“CREATE OR REPLACE <table_name> AS SELECT * FROM <view>;”创建或替换表。 - Alex Offshore

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接