MySQL:复制包括外键的表结构

24

我知道如何使用create new_table like old_table复制表格,但是这并不会复制外键约束。我还可以对来自show create table old_table的结果进行字符串操作(使用正则表达式替换表名和外键约束名),但那似乎容易出错。是否有更好的方法复制一个表的结构,包括外键?


2
你曾经成功地做到这件事吗?我现在正在尝试弄清楚它,但实际上无法让它工作。 - Pim Jager
1
很遗憾,CREATE TABLE LIKE命令创建了我们95%的表...我写了一篇文章,详细介绍了复制数据库结构的最终解决方案,如果有用的话可以看看。(https://medium.com/@igorsantos07/a-not-so-small-rant-on-mysql-based-techniques-to-copy-database-structures-4333f8ff8384#.8qiega4cq)。 我把几个相关的问题粘在了一起,就像这个问题所提出的那样。 - igorsantos07
6个回答

6
也许您可以编写一个过程,在create table like之后准备ALTER TABLE ...语句,基于以下信息:
SELECT * 
FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE 
WHERE TABLE_NAME LIKE '<table_name>' 
AND TABLE_SCHEMA = '<db_name>'
AND REFERENCED_TABLE_NAME IS NOT NULL;

4

如果可以使用一点辅助脚本,你可以利用SHOW CREATE TABLE的几行代码来实现(以下是PHP示例,但概念适用于任何语言):

// Get the create statement
$retrieve = "SHOW CREATE TABLE <yourtable>";

$create = <run the $retrieve statement>

// Isolate the "Create Table" index
$create = $create['Create Table'];

// Replace old table name with new table name everywhere
$create = preg_replace("/".$newname."/", $oldname, $create);

// You may need to rename foreign keys to prevent name re-use error.
// See https://dev59.com/wuo6XIcBkEYKwwoYPR_f
$create = preg_replace("/FK_/", "FK_TEMP_", $create);    

// Create the new table
<run the $create statement>

这不是非常优雅,但目前为止它可以工作。我在测试环境中做这个,所以把它放在我的 setUp() 方法中。


1
如果你正在处理脚本操作,这是最好的方法。很遗憾CREATE TABLE LIKE只完成了95%。我写了一篇关于复制数据库的最终解决方案的文章,如果对任何人有用的话,可以看看我的文章。我将几个相关问题粘在一起,就像这个问题所展示的那样。 - igorsantos07

3
Wrikken 的回答启发了我。让我来扩展一下。
事情更加复杂。参见:http://dev.mysql.com/doc/refman/5.1/en/create-table.html。它说,即使是 TEMPORARY 表和其他东西也会出现问题。Wrikken 提到的解决方案是一个不错的方法,但是你需要至少再进行一次查找以获取关于 UPDATEDELETE 规则的信息。
SELECT * 
FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS
WHERE TABLE_NAME LIKE '<table_name>' 
AND CONSTRAINT_SCHEMA = '<db_name>';

所以,获取一个简化任务的工具可能是个好主意。我个人使用Adminer(https://sourceforge.net/projects/adminer/)。它带有导出整个数据库(包括所有表、触发器、外键等)的选项。一旦你将其导出(使用SQL语法),你就可以轻松更改数据库名称并重新导入它。我在项目的错误部分写了关于这个的内容(请参见票号380)。
也许你已经有了自己喜欢的数据库管理器,不想再用另一个。那么你可以按照以下步骤操作:
  1. 使用mysqldump转储数据库->你会得到file.sql
  2. 创建一个新的数据库
  3. 在新的数据库中执行file.sql
Adminermysqldump都有选择特定表格的选项,因此您不必导出整个数据库。如果只需要结构而不需要数据,请在mysqldump中使用-d选项或在Adminer中单击该选项。

0

如果您只想清空您的表格,您可以将所有相关数据复制到副本表中。然后清除并复制回去。结果是,您保留了您的外键。

CREATE TABLE IF NOT EXISTS t_copy LIKE t_origin;

INSERT INTO t_copy 
SELECT  t_origin.*      
FROM t_origin;


SET FOREIGN_KEY_CHECKS = 0;

TRUNCATE t_origin;

INSERT INTO t_origin
SELECT t_copy.* 
FROM t_copy;

DROP TABLE t_copy;

SET FOREIGN_KEY_CHECKS = 1; 

这实际上是一个很好的替代方案。我不明白为什么会有负评。我给你点赞。 - DrGeneral

0
我创建了一个Bash脚本,将一个表复制到另一个数据库中,并通过在键和约束上添加“_1”来修改它们:
mysqldump -h ${host_ip} -u root -p${some_password} ${some_database} ${some_table}  > some_filename
sed -i -r -e 's@KEY `([a-zA-Z0-9_]*)`@KEY `\1_1`@g' -e 's@CONSTRAINT `([a-zA-Z0-9_]*)`@CONSTRAINT `\1_1`@g' some_filename
mysql -h ${host_ip} -u root -p${some_password} ${some_new_database} < some_filename

这也适用于新的数据库实例,但是'sed'命令不是必需的。只有在源数据库和目标数据库位于同一实例时才需要。


0
如果您有phpMyAdmin,可以仅导出表结构,然后在.sql文件中更改旧表名为新表名,并将其重新导入。这是相当快捷的方法。

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