ChatGPT解决这个技术问题 Extra ChatGPT

Laravel 迁移更改以使列可为空

我使用未签名的 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();
}

k
kjones

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();
        });               

}

谢谢。但是我怎样才能反其道而行之呢?如何将列更改为不可为空?有任何想法吗?
@algorhythm 你试试这个' $t->string('name', 100)->change();'
您需要需要教义\dbal 才能迁移
@algorhythm ->nullable(false) 将让您再次更改该列。
->change() 要求您安装 Doctrine DBAL 包,并且它本身并不能识别 laravel 开箱即用的所有相同列类型。例如,double 不是 DBAL 可识别的列类型。
T
Tomerikoo

请注意,这仅在 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;');
}

这是 L5 最完整的答案,但应该提到的是,如果 'user_id' 是外键,它应该是,除非你运行 'DB::statement('SET FOREIGN_KEY_CHECKS = 0');'第一的。完成后将其设置回 1。
谢谢,nullable(false) 让我免于被扯掉头发,因为 nullable() 没有很好的文档记录,并且没有 notNull() 函数。
这不适用于带有 postgres 的外键。尝试 SET FOREIGN_KEY_CHECKS = 0 会出错。您可能需要使用原始查询来更改表的约束。见这里:postgresql.org/docs/current/static/sql-altertable.html
这打破了我的测试。测试开始运行,然后挂起。我想第一次回滚会导致这种情况。导致 MySQL 和 SQLite 的挂起测试。
U
Unnawut

我假设您正在尝试编辑已添加数据的列,因此在不丢失数据的情况下删除列并再次添加为可空列是不可能的。我们将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;');
}

对于 Laravel 4,将 query 替换为 statement
谢谢@Razor。相应地更新了我的答案。
在第二个代码块的 down 函数中,SQL 语句应以 NOT NULL 结尾。 (第三个例子中的 down 函数是正确的。)
Y
Yauheni Prakopchyk

他是 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();
    });
}

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


T
Tomerikoo

对于 Laravel 5+,添加到 Dmitri Chebotarevanswer

在需要教义/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');
}

k
ken

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

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

然后只需安装

composer require doctrine/dbal


这让我很生气,所以我继续让异常/解决方案更容易理解:github.com/laravel/framework/pull/10002
F
Fefar Ravi

安装 Composer 包:

composer require doctrine/dbal

成功安装 composer 包后,我们可以使用迁移命令更改数据类型和更改列名。

句法:

php artisan make:migration alter_table_[table_name]_change_[column_name] --table=[table_name]

例子:

php artisan make:migration alter_table_sessions_change_user_id --table=sessions

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class AlterTableSessionsChangeUserId extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::table('sessions', function (Blueprint $table) {
            $table->integer('user_id')->unsigned()->nullable()->change();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('sessions', function (Blueprint $table) {
            $table->dropColumn('user_id');
        });
    }
}

并运行:php artisan migrate

或者

或表刷新以更改列名。不使用 change 方法。

Schema::create('throttle', function(Blueprint $table)
{
    $table->increments('id');
    # old code
    $table->integer('user_id')->unsigned();
    # new code
    $table->integer('user_id')->unsigned()->nullable();
}

注意:下面的命令从表中清除数据。

php artisan migrate:refresh --path=/database/migrations/2021_09_31_050851_create_throttle_table.php

S
Sameer

添加到 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;
');

A
Adil

试试看:

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

它不会改变现有的列
您最后忘记了 ->change,仅提及 Laravel 5+
您需要要求 composer require doctrine/dbal
D
Debiprasad

对于 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;');
}

A
Abdelalim Hassouna

我不得不使用 nullable(true)

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