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 乌班图ip地址配置及远程SSH
  • ¥15 怎么让点阵屏显示静态爱心,用keiluVision5写出让点阵屏显示静态爱心的代码,越快越好
  • ¥15 PSPICE制作一个加法器
  • ¥15 javaweb项目无法正常跳转
  • ¥15 VMBox虚拟机无法访问
  • ¥15 skd显示找不到头文件
  • ¥15 机器视觉中图片中长度与真实长度的关系
  • ¥15 fastreport table 怎么只让每页的最下面和最顶部有横线
  • ¥15 java 的protected权限 ,问题在注释里
  • ¥15 这个是哪里有问题啊?