我正在创建一个PHP脚本来比较两个数据库的模式。
我已经设法检查有关删除/添加的表,列,索引,引用的架构更改,但是当涉及到重命名的列时,我有点卡住了。
在以下示例中,源数据库包含最新的架构,目标数据库包含类似的架构但可能已过期。
先决条件:
以目标数据库中的以下模式为例。
Field Type Null Key Default Extra
field1 int(11) NO NULL
field2 int(11) NO NULL
field3 int(11) NO NULL
然后在源数据库中假设以下模式。
Field Type Null Key Default Extra
field1 int(11) NO NULL
field4 int(11) NO NULL
field3 int(11) NO NULL
在未明确了解发生的情况的情况下,我无法通过field2
或field4
确定DROP, ADD AFTER
是否已更改为CHANGE COLUMN
。以下两个查询在表结构方面实现了相同的结果,但使用前者丢失了数据。
(1) ALTER TABLE `demo` DROP `field2`
ALTER TABLE `demo` ADD `field4` INT( 11 ) NOT NULL AFTER `field1`
(2) ALTER TABLE `demo` CHANGE `field2` `field4` INT( 11 ) NOT NULL
我显然可以删除旧列名并创建一个新列,但这会丢失原始列中的任何数据。我需要使用ALTER TABLE table CHANGE COLUMN field new_name structure;
查询,而不是DROP column FROM table
后跟ALTER TABLE table
ADD column definition;
我希望我可以使用DDL触发器来跟踪架构中的更改,并将此类更改的记录插入源数据库中的表中。我以后可以查询此表以确定某个列是如何形成的。但是,据我所知,它不可能在MySQL中运行DDL查询的触发器,这会排除记录这些更改。我在MySQL Forge上阅读了这个工作日志(WL#2418: DDL Triggers)(现在驻留在MySQL Developer Zone中),但它似乎还在等待实现。
有没有一种方法可以更新表以匹配关于重命名列的架构而不会丢失数据?
我已经查看了MySQLDiff之类的内容,但它需要构建到现有的代码中,所以我必须自己构建它。
为每个列添加注释,这是一个唯一的数字或字符串(为了参数,将其称为哈希)。查询information_schema表以检索此值并在每列上进行比较。如果它是唯一的那么它是一个新列,或者如果它匹配一个哈希而不是一个名称或结构,那么它就被重命名/重新配置。
比较架构,如果有新列 - 检查它相对于相邻列的位置。如果新列的名称与缺少的列的名称相同,则比较该列的结构。如果匹配,请考虑重命名。如果没有,请考虑删除然后添加。
答案 0 :(得分:1)
我认为您不应该以这种方式同步架构。您应该在每次更改任何内容时检查迁移脚本到源代码,然后在数据库中有一个表记录应用了哪些迁移。这样,您可以确保所有迁移都应用于所有数据库。例如`
CREATE TABLE `ddl_version` (
version` varchar(32) NOT NULL,
`applied_on` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
UNIQUE KEY `version` (`version`)
)`
答案 1 :(得分:0)
ALTER TABLE table
CHANGE COLUMN old_col_name
new_col_name column_definition;
这会更改列名而不会丢失列中的数据(除非您也更改数据类型,并且新数据类型小于旧数据类型,例如将BIGINT更改为SMALLINT)。
遗憾的是,此命令要求您重复列的当前定义,例如数据类型,NOT NULL和其他选项。 MySQL中没有命令可以简单地重命名列。
CHANGE COLUMN子句是标准SQL的MySQL扩展,它不提供重命名列的语法。
如果您想坚持使用标准SQL,另一种解决方案是添加新列,将旧列中的数据复制到新列,然后删除旧列:
ALTER TABLE table ADD COLUMN new_col_name column_definition;
UPDATE table SET new_col_name = old_col_name;
ALTER TABLE table DROP COLUMN old_col_name;
答案 2 :(得分:0)
这里最大的问题是,如果为同一个表更改了多于1个列名(相同类型),则无法确定哪个列已更改为哪个列。 (可能仍然可以选择实际比较数据,并希望两个表中的某些数据相同,这样就可以推断出哪些列改变了什么,但它完全不可靠)
还有1(或更多)字段已更改且添加1(或更多)的问题,您将再次运行与上述相同的问题。
上面提到的MySQLDiff可以告诉你哪些字段是新的,哪些字段是旧的(更像是新表等),但是它无法告诉你哪个列名被改为什么字段而且它没有?甚至尝试。 (没有软件能够可靠地做到这一点,特别是如果db之间的数据不一样) 你可以看到它的作用:mysql-1.5.0 / library / database.lib.php和mysql-1.5.0 / library / generator.lib.php
我强烈建议的一件事是在开发团队中引入一个非常简单的过程。 - 每次更改数据库结构(或系统工作所需的任何记录)都应记录到例如。 db_changes.sql文件,受版本控制。对于每个新版本,如果需要对db进行此类更改,则擦除db_changes.sql文件,记录更改并将其另存为新修订。这样就可以对数据库结构的更改进行适当修改,并且应用它们只需要区分2个修订点。 (MysqlWorkbench是客户端之一,如果您更改表,它将显示它将在内部运行的查询,如果您的开发人员需要使用客户端)
答案 3 :(得分:0)
MySQL不支持DDL触发器。我可以在他们的工作日志中看到他们为服务器7.1计划了它。
任务ID为WL#2418。
答案 4 :(得分:0)
没有办法检测到这一点,但如果您需要本地机器,那么有一种方法可以做到这一点。
table
mysql.general_log
表格中。SELECT * FROM mysql.general_log WHERE argument LIKE 'ALTER%'
之类的查询,为您提供与数据库修改相关的所有SQL语句,包括列重命名。希望有所帮助..