Laravel迁移更改以使列为空


194

我使用unsigned创建了迁移user_id。如何user_id在新迁移中进行编辑以使其同样成功nullable()

Schema::create('throttle', function(Blueprint $table)
{
    $table->increments('id');
    // this needs to also be nullable, how should the next migration be?
    $table->integer('user_id')->unsigned();
}

Answers:


261

Laravel 5现在支持更改列;这是官方文档中的示例:

Schema::table('users', function($table)
{
    $table->string('name', 50)->nullable()->change();
});

资料来源:http : //laravel.com/docs/5.0/schema#changing-columns

Laravel 4不支持修改列,因此您需要使用另一种技术,例如编写原始SQL命令。例如:

// getting Laravel App Instance
$app = app();

// getting laravel main version
$laravelVer = explode('.',$app::VERSION);

switch ($laravelVer[0]) {

    // Laravel 4
    case('4'):

        DB::statement('ALTER TABLE `pro_categories_langs` MODIFY `name` VARCHAR(100) NULL;');
        break;

    // Laravel 5, or Laravel 6
    default:                

        Schema::table('pro_categories_langs', function(Blueprint $t) {
            $t->string('name', 100)->nullable()->change();
        });               

}

3
为此。但是我该如何做相反呢?如何将列更改为不可为空?有任何想法吗?
algorhythm 2015年

@algorhythm您是否尝试使用此'$ t-> string('name',100)-> change();'
MURATSPLAT

7
您需要要求doctrine \ dbal才能迁移
younes0 2015年

33
@algorhythm ->nullable(false)将让您再次更改该列。
科林

9
-> change()要求您安装Doctrine DBAL软件包,并且它不能固有地识别laravel可用的所有相同列类型。例如,对于DBAL来说,double不能识别列类型。
文森特

174

这是将来的读者的完整答案。请注意,这仅在Laravel 5+中可行。

首先,您需要教义/ dbal软件包:

composer require doctrine/dbal

现在,在迁移中,您可以执行以下操作以使该列可为空:

public function up()
{
    Schema::table('users', function (Blueprint $table) {
        // change() tells the Schema builder that we are altering a table
        $table->integer('user_id')->unsigned()->nullable()->change();
    });
}

您可能想知道如何还原此操作。遗憾的是,不支持此语法:

// Sadly does not work :'(
$table->integer('user_id')->unsigned()->change();

这是还原迁移的正确语法:

$table->integer('user_id')->unsigned()->nullable(false)->change();

或者,如果您愿意,可以编写原始查询:

public function down()
{
    /* Make user_id un-nullable */
    DB::statement('UPDATE `users` SET `user_id` = 0 WHERE `user_id` IS NULL;');
    DB::statement('ALTER TABLE `users` MODIFY `user_id` INTEGER UNSIGNED NOT NULL;');
}

希望您会发现此答案有用。:)


3
这是L5的最完整答案,但是应该指出的是,如果'user_id'是外键,应该是外键,除非运行'DB :: statement('SET FOREIGN_KEY_CHECKS = 0');' 第一。完成后将其设置回1。
rzb

1
谢谢,nullable(false)使我免于拔掉头发,因为nullable()没有充分记录,也没有任何notNull()功能。
扎克·莫里斯

这对于使用postgres的外键不起作用。尝试SET FOREIGN_KEY_CHECKS = 0给出一个错误。您可能需要使用原始查询来更改表的约束。看到这里:postgresql.org/docs/current/static/sql-altertable.html
rrrafalsz

这打破了我的考验。测试开始运行,然后挂起。我想第一次回滚会导致这种情况。导致MySQL和SQLite的挂起测试。
Thomas Praxl

155

我假设您正在尝试编辑已添加数据的列,因此在不丢失数据的情况下,不可能删除该列并将其再次添加为可空列。我们将alter现有的列。

但是,Laravel的架构生成器仅支持重命名列,不支持修改列。因此,您将需要运行原始查询来执行它们,如下所示:

function up()
{
    DB::statement('ALTER TABLE `throttle` MODIFY `user_id` INTEGER UNSIGNED NULL;');
}

为了确保您仍然可以回滚迁移,我们也会做down()

function down()
{
    DB::statement('ALTER TABLE `throttle` MODIFY `user_id` INTEGER UNSIGNED NOT NULL;');
}

需要注意的是,由于要在可空值和不可空值之间进行转换,因此需要确保在迁移之前/之后清除数据。因此,在两种迁移脚本中都这样做:

function up()
{
    DB::statement('ALTER TABLE `throttle` MODIFY `user_id` INTEGER UNSIGNED NULL;');
    DB::statement('UPDATE `throttle` SET `user_id` = NULL WHERE `user_id` = 0;');
}

function down()
{
    DB::statement('UPDATE `throttle` SET `user_id` = 0 WHERE `user_id` IS NULL;');
    DB::statement('ALTER TABLE `throttle` MODIFY `user_id` INTEGER UNSIGNED NOT NULL;');
}

7
对于Laravel 4,替换querystatement
Razor

2
谢谢@剃刀。相应地更新了我的答案。
Unnawut 2014年

1
down第二个代码块中的函数中,SQL语句应以结尾NOT NULL。(down第三个示例中的功能正确。)
Scott Weldon 2015年

46

他是Laravel 5的完整移民:

public function up()
{
    Schema::table('users', function (Blueprint $table) {
        $table->unsignedInteger('user_id')->nullable()->change();
    });
}

public function down()
{
    Schema::table('users', function (Blueprint $table) {
        $table->unsignedInteger('user_id')->nullable(false)->change();
    });
}

关键是,您可以nullable通过false作为参数传递来删除。


16

如果您碰巧更改了列并偶然发现

'Doctrine\DBAL\Driver\PDOMySql\Driver' not found

然后安装

composer require doctrine/dbal


1
这让我有点难受,
Beau Simensen

9

与Laravel 5+一样,增加了Dmitri Chebotarev的答案。

要求教义/ dbal软件包后:

composer require doctrine/dbal

然后,您可以使用可为空的列进行迁移,如下所示:

public function up()
{
    Schema::table('users', function (Blueprint $table) {
        // change() tells the Schema builder that we are altering a table
        $table->integer('user_id')->unsigned()->nullable()->change();
    });
}

要还原操作,请执行以下操作:

public function down()
{
    /* turn off foreign key checks for a moment */
    DB::statement('SET FOREIGN_KEY_CHECKS = 0');
    /* set null values to 0 first */
    DB::statement('UPDATE `users` SET `user_id` = 0 WHERE `user_id` IS NULL;');
    /* alter table */
    DB::statement('ALTER TABLE `users` MODIFY `user_id` INTEGER UNSIGNED NOT NULL;');
    /* finally turn foreign key checks back on */
    DB::statement('SET FOREIGN_KEY_CHECKS = 1');
}

3

添加至Dmitri Chebotarev答案,

如果您想一次更改多个列,则可以像下面这样

DB::statement('
     ALTER TABLE `events` 
            MODIFY `event_date` DATE NOT NULL,
            MODIFY `event_start_time` TIME NOT NULL,
            MODIFY `event_end_time` TIME NOT NULL;
');


2

对于Laravel 4.2,Unnawut的上述答案是最好的答案。但是,如果您使用表前缀,则需要稍微更改代码。

function up()
{
    $table_prefix = DB::getTablePrefix();
    DB::statement('ALTER TABLE `' . $table_prefix . 'throttle` MODIFY `user_id` INTEGER UNSIGNED NULL;');
}

为了确保您仍然可以回滚迁移,我们也会做down()

function down()
{
    $table_prefix = DB::getTablePrefix();
    DB::statement('ALTER TABLE `' . $table_prefix . 'throttle` MODIFY `user_id` INTEGER UNSIGNED NOT NULL;');
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.