dongnvwang8591 2018-09-13 20:53
浏览 89
已采纳

如何在Laravel迁移中将不可为空的列安全地添加到现有表中?

I would like to add an un-nullable column to an existing table with some rows in Laravel migration. In SQL, I understand such an action should be performed inside a transaction in the order of

  1. adding a column
  2. initialising the column
  3. making it un-nullable

so as to guarantee

  • the initialisation to be performed without disrupting the DB integrity, and
  • ALTER TABLE not to violate the NOT NULL constraint,

The following is an example PostgreSQL code (assuming users table has a column old_col), referring to an answer:

BEGIN TRANSACTION;
  ALTER TABLE users ADD COLUMN new_col integer;
  UPDATE users SET new_col = old_col + 1;
  ALTER TABLE users ALTER COLUMN new_col SET NOT NULL;
COMMIT;

An ordinary Laravel migration file like this would not work.

public function up()
{
    Schema::table('users', function($table) {
        $table->integer('new_col');  // ->nullable(false) // later?
    });
}

How can one implement a SQL transaction or its equivalent in Laravel migration?

NOTE (edited):
If you want to set up the default value, and if you do not need to (absolutely simultaneously) update the column for the existing rows as a function of some values of each row, then you can simply specify ->default(0) or something like that in the migration file (and avoid all the tricks!). My intention of the question was not to set up the default for the column to add.

  • 写回答

3条回答 默认 最新

  • doulu5109 2018-09-13 22:53
    关注

    The solution with three queries:

    DB::transaction(function () {
        Schema::table('users', function (Blueprint $table) {
            $table->integer('id_cloned')->nullable();
        });
    
        App\Models\User::query()->update([
            'id_cloned' => DB::raw('id + 1'),
            'updated_at' => DB::raw('now()') // if you want to touch the timestamp
        ]);
    
        Schema::table('users', function (Blueprint $table) {
            $table->integer('id_cloned')->nullable(false)->change();
        });
    });
    

    Alternative solution without DB::raw parts, but will generate separate update query for every record:

    DB::transaction(function () {
        Schema::table('users', function (Blueprint $table) {
            $table->integer('id_cloned')->nullable();
        });
    
        foreach (App\Models\User::all() as $row) {
            $row->id_cloned = $row->id + 1;
            $row->save();
        }
    
        Schema::table('users', function (Blueprint $table) {
            $table->integer('id_cloned')->nullable(false)->change();
        });
    });
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(2条)

报告相同问题?

悬赏问题

  • ¥15 算能科技20240506咨询(拒绝大模型回答)
  • ¥15 自适应 AR 模型 参数估计Matlab程序
  • ¥100 角动量包络面如何用MATLAB绘制
  • ¥15 merge函数占用内存过大
  • ¥15 Revit2020下载问题
  • ¥15 使用EMD去噪处理RML2016数据集时候的原理
  • ¥15 神经网络预测均方误差很小 但是图像上看着差别太大
  • ¥15 单片机无法进入HAL_TIM_PWM_PulseFinishedCallback回调函数
  • ¥15 Oracle中如何从clob类型截取特定字符串后面的字符
  • ¥15 想通过pywinauto自动电机应用程序按钮,但是找不到应用程序按钮信息