すでにレコードがあるテーブルにデフォルト値を設定せずNOT NULL制約をつけたカラムを追加する

すでにレコードがあるテーブルにデフォルト値を設定せずにNOT NULL制約をつけたカラムを追加しようとすると、追加したカラムのレコードの値をNULLにする訳にはいかずエラーになってしまします。

これらに対応するには一度デフォルト値を指定する方法と、値をプログラム側で変更する2つの方法がありそうなのでSQLとRailsのmigrationで試してみました。

一度デフォルト値を指定する

  1. デフォルト値、NOT NULL制約を指定したカラムを追加
  2. default値の設定を外す

この方法はアプリケーションを動かしながら変更できるという利点があるので、この方法で十分な場合はこの方法を使うと良いと思います。

SQL

ALTER TABLE users ADD group_id int DEFAULT 1 NOT NULL;
ALTER TABLE users MODIFY group_id int(11) NOT NULL;

Ruby on Rails(migrationファイル)

def up
  add_column :users, :group_id, :integer, null: false, default: 1
  change_column_default :users, :group_id, nil
end

値をプログラム側で変更する方法

  1. NOT NULL制約を指定しないカラムを追加
  2. もともとあったレコードの追加したカラムのレコードに値を入れる
  3. NOT NULL制約の設定に変更する

この方法は過去のデータをプログラム側で制御できるという利点があります。 ただし、アプリケーションを動かしながらだと過去のレコード追加してからNOT NULL制約をつけるまでに新しくレコードが入ってしまうとエラーが出てしまうという問題があるので一度止める必要がありそうです。

SQL

ALTER TABLE users ADD group_id int;
UPDATE users SET users.group_id = 1;
ALTER TABLE users MODIFY group_id int(11) NOT NULL;

Ruby on Rails(migrationファイル)

def up
  add_column :users, :group_id, :integer
  User.update_all(group_id: 1)
  change_column_null :users, :group_id, false
end

参照