创建表或修改表结构时的语法:创建表,否则修改表。

4

这似乎是一个简单的问题,但经过一段时间的搜索,我仍然无法找到答案。

我目前在本地数据库中使用的Web应用程序,有一个MySQL表,并且在远程服务器上也有相同的表。现在,我正在使用PHP通过 CREATE TABLE IF NOT EXISTS 命令在数据库上创建表:

CREATE TABLE IF NOT EXISTS users (  
  `id` int(10) NOT NULL AUTO_INCREMENT,  
  `username` varchar(18) NOT NULL,  
  PRIMARY KEY (`id`)  
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=2 ;

然而,假设我对本地数据库进行修改,例如添加一列。每次更改本地数据库时都必须去更改远程数据库将会非常麻烦。是否有更简单的方法运行代码以创建表(如果不存在),并且如果存在,则确保其结构与创建表结构相匹配?
以下是一个示例,以使我试图传达的内容更加清晰。假设在本地数据库中我有一个用户表,并且我决定在我的Web应用程序中添加另一个列“password”。因此,我转到本地数据库并添加了一个“password”列。是否有PHP / MySQL代码可以运行以检查用户表是否存在,如果存在,则确保它具有“password”列,如果不存在,则添加它?

+1 你的问题对许多数据库程序员非常有帮助。 - Lajos Arpad
4个回答

2
你实际上需要的是迁移,例如,你需要一个模式管理工具,让你能够通过版本化的代码差异来管理数据库结构。
比如,在你描述的场景中,你首先需要创建一个脚本来创建表,比如 001_create_user_table.sql。然后,你可以使用模式管理器来连接并部署这些变更到你的数据库中。
当你想要更改或添加一些内容时,你只需要编写另一个脚本,比如 002_Add_Password_Column_To_User_Table.sql。只需填写执行该更改的代码,然后再次运行模式管理器。
通常情况下,你会告诉模式管理器遍历所有现有的迁移文件。每次运行时,模式管理器都会更新数据库中的变更日志表,因此当你运行它时,它就知道应该应用哪些脚本。
好处在于,你可以将这些迁移添加到你的常规版本控制系统中,这样你就会始终知道你的应用程序的哪个版本拥有哪个数据库模式。而且你将为它们拥有一个适当的变更日志。

你会推荐哪个模式管理工具?我不需要非常复杂的东西,只是一个简单的工具来管理数据库结构,就像你所说的那样。 - element119
@Chromium 从链接中给出的选项中,尽管在迁移过程中存在一些缺点,我会选择Phing+DBDeploy,主要是因为它使用普通的SQL文件,而且我可以在任何其他部署任务中使用Phing。另外两个选项只是“模式管理器”。Akrabat的模式管理器可能更容易设置和使用。我从未使用过MDB2_Schema。 - Gordon

1
直接回答您的问题,您可以创建临时过程来检测字段是否存在,例如使用以下查询:
SHOW COLUMNS FROM table_name LIKE 'column_name';
然而在实际应用中,数据库更改通常被分为三个脚本。一个创建脚本和两个增量脚本,一个向上,一个向下。然后对数据库进行版本控制,以便您知道数据库在任何给定时间的状态。

0

如果要特别检查一个密码列,可以使用DESCRIBE

$colExists = false;
$res = mysql_query('DESCRIBE `users`');
while ($row = mysql_fetch_assoc($res)) {
    if ($row['Field'] == 'password') {
        $colExists = true;
        break;
    }
}

if (!$colExists) {
    // create column
}

然而,你应该研究复制或其他自动化工具,看看它们是否对你更好。


0

按照以下步骤进行操作(您可以轻松地在PHP中实现,我假设表的名称为Foo)

1.) 运行以下代码:

desc Foo

2.) 根据第一步的结果制作创建表命令(您应该这样做)

3.) 将要替换的现有表中的数据存储在变量中(可选项,只有在您可能使用旧表中的数据时才需要)

4.) 修改从步骤3中提取的行,使其与新定义兼容(可选项,只有在您可能使用旧表中的数据时才需要)

5.) 获取您的新Foo表中的行

6.) 合并步骤4和5中得到的结果(可选项,只有在您可能使用旧表中的数据时才需要)

7.) 对旧表运行一个删除表命令

8.) 生成一个replace into命令将所有行插入到新创建的Foo表中(您可以在这里阅读更多信息)

完成以上步骤后,您将获得表的新版本。如果您的表太大,可以执行CREATE TABLE IF NOT EXISTS命令,如果不成功,则运行alter命令。

此外,您可以创建一个库来执行这些步骤,并在未来使用它,而不是多次解决同样的问题。

编辑: 您可以使用此函数连接数据库:mysql-connect(文档here) 您可以使用此函数运行查询:mysql-query(文档here

根据第一步,您将获得字段名称(假设您将其存储在名为$bar的变量中),并且您可以使用结果生成选择命令(连接到具有重要数据的数据库。它可能是两者之一):

$field_list = "1";
foreach ($bar as $key => $value)
    $field_list.= ",".$bar[$key];

mysql_connect(/*connection data*/);
mysql_query("select ".$field_list." from Foo");

您可以使用新资源来构建插入命令,在删除重建后插入所有重要数据(有关资源的更多信息请阅读此处,有关如何生成插入命令的信息,请阅读此处,但我建议您使用replace into而不是insert,它的作用类似于insert,只是如果已经存在该行,则替换该行,这比插入更好,在此处了解更多)。

因此,使用mysql_connect和mysql_query,mysql_query函数返回的资源稍后可以用于replace into(我现在已经链接了您需要的所有URL,所以我相信您会解决问题。),之前没有具体说明,对此我深表歉意。


我该如何存储现有表中的数据(即,使用哪个具体命令)?然后我应该使用什么来将行插入到新生成的表中? - element119

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