如何迁移更改列类型?

How to migration change columns type?

我得到一个错误,当我尝试从字符串到文本的列类型时,具有Laravel的迁移功能。

文件:{data_time}_change_db_structure.php

public function up()
  {
    Schema::table('service_request_type', function (Blueprint $table) {
      $table->dropIndex(['sro_key_group']);

      $table->text('sro_key_group')->change();
      $table->renameColumn('sro_key_group', 'tags');
    });
  }

这是原始迁移创建 table 文件。

public function up()
  {
    Schema::create('service_request_type', function (Blueprint $table) {
      $table->engine = 'InnoDB';
      ...
      $table->string('sro_key_group', 100)->nullable()->index();
      ...
    });
  }

我收到错误。

[Illuminate\Database\QueryException]
SQLSTATE[42000]: Syntax error or access violation: 1170 BLOB/TEXT column 'sro_key_group' used in key specification without a key length (SQL: ALTER TABLE service_request_type CHANGE sro_key_group sro _key_group TEXT DEFAULT NULL COLLATE utf8_unicode_ci)

                                                                                                                                          [Doctrine\DBAL\Driver\PDOException]                                   

SQLSTATE[42000]: Syntax error or access violation: 1170 BLOB/TEXT column 'sro_key_group' used in key specification without a key length

                                                                                                                                          [PDOException]                                                        

SQLSTATE[42000]: Syntax error or access violation: 1170 BLOB/TEXT column 'sro_key_group' used in key specification without a key length

怎么了?我已经在 composer.json.

中安装了 doctrine/dbal

啊啊啊啊啊啊……

我得到了答案。

public function up()
  {
    Schema::table('service_request_type', function (Blueprint $table) {
      $table->dropIndex(['sro_key_group']);
    });
    Schema::table('service_request_type', function (Blueprint $table) {
      $table->text('sro_key_group')->nullable()->change();
    });
    Schema::table('service_request_type', function (Blueprint $table) {
      $table->renameColumn('sro_key_group', 'tags');
    });
  }

Hmmmmmmm 那是什么鬼?

您需要分三步完成此操作,使用三个单独的迁移,或如您在答案中所示调用三个 table()

第一个问题是,即使您已经按照您希望它们执行的顺序(以及它们需要执行的顺序)编写语句,模式构建器实际上会重新排列顺序,以便 "change"语句先执行。架构生成器将新列和更改的列视为 "implied" 语句,并将它们移动到命令堆栈的顶部到 运行。但是,重命名语句不被视为 "change" 语句。

因此,即使您已将代码编写为:

[
    remove index,
    change column from varchar to text,
    rename column,
]

架构构建器将实际执行:

[
    change column from varchar to text,
    remove index,
    rename column,
]

现在,由于更改命令是在列从索引中删除之前发生的,因此您会收到 1170 错误。

下一个问题是尝试在同一上下文中更改列和重命名列。实现请求更改的 SQL 是通过执行架构差异生成的,但是两个架构差异将在实际进行任何更改之前完成。因此,从 varchartext 的第一个更改将生成适当的 SQL 来进行该更改,但随后重命名该列的第二个更改实际上将生成 SQL 更改在重命名时将列返回到文本字段。

要解决这些问题,您可以创建三个迁移,其中第一个迁移只是删除索引,第二个迁移更改类型,然后第三个迁移重命名它,或者您可以保留一个迁移并运行 三个 table() 语句。

public function up()
{
    // make sure the index is dropped first
    Schema::table('service_request_type', function (Blueprint $table) {
        $table->dropIndex(['sro_key_group']);
    });

    // now change the type of the field
    Schema::table('service_request_type', function (Blueprint $table) {
        $table->text('sro_key_group')->nullable()->change();
    });

    // now rename the field
    Schema::table('service_request_type', function (Blueprint $table) {
        $table->renameColumn('sro_key_group', 'tags');
    });
}