Как решить "Невозможно добавить столбец NOT NULL со значением по умолчанию NULL" в SQLite3?
Я получаю следующую ошибку при попытке добавить столбец NOT NULL в существующую таблицу. Почему это происходит? Я попробовал rake db: reset, считая, что существующие записи являются проблемой, но даже после сброса БД проблема сохраняется. Не могли бы вы помочь мне понять это.
Файл миграции
class AddDivisionIdToProfile < ActiveRecord::Migration
def self.up
add_column :profiles, :division_id, :integer, :null => false
end
def self.down
remove_column :profiles, :division_id
end
end
Сообщение об ошибке
SQLite3:: SQLException: не может добавить столбец NOT NULL со значением по умолчанию NULL: ALTER TABLE "profiles" ADD "division_id" integer NOT NULL
Ответы
Ответ 1
У вас уже есть строки в таблице, и вы добавляете новый столбец division_id
. Это нужно что-то в этом новом столбце в каждой из существующих строк.
SQLite обычно выбирает NULL, но вы указали, что оно не может быть NULL, так что это должно быть? У него нет возможности узнать.
Увидеть:
Эта рекомендация для блога заключается в добавлении столбца без ограничения not null, и он будет добавляться с NULL в каждой строке. Тогда вы можете заполнить значения в division_id
, а затем использовать change_column
добавить не нулевое ограничение.
См. Блоги, на которые я ссылался, для описания скрипта миграции, который выполняет этот трехэтапный процесс.
Ответ 2
Это (что я считаю) сбой с SQLite. Эта ошибка возникает, если в таблице есть какие-либо записи.
При добавлении таблицы с нуля вы можете указать NOT NULL, что вы делаете с нотой ": null = > false". Однако при добавлении столбца это невозможно. Спецификация SQLite говорит, что для этого вам нужно иметь по умолчанию, что является плохим выбором. Добавление значения по умолчанию не является опцией, потому что оно нарушает цель использования внешнего ключа NOT NULL, а именно целостности данных.
Здесь можно обойти этот глюк, и вы можете сделать все это в той же миграции. ПРИМЕЧАНИЕ. Это относится к случаю, когда у вас еще нет записей в базе данных.
class AddDivisionIdToProfile < ActiveRecord::Migration
def self.up
add_column :profiles, :division_id, :integer
change_column :profiles, :division_id, :integer, :null => false
end
def self.down
remove_column :profiles, :division_id
end
end
Мы добавляем столбец без ограничения NOT NULL, а затем сразу же изменяем столбец, чтобы добавить ограничение. Мы можем это сделать, потому что SQLite, по-видимому, очень обеспокоен при добавлении столбца, он не настолько разборчив с изменениями столбцов. Это ясный дизайн запаха в моей книге.
Это определенно взлом, но он короче нескольких миграций, и он все равно будет работать с более надежными базами данных SQL в вашей рабочей среде.
Ответ 3
Если у вас есть таблица с существующими строками, вам необходимо обновить существующие строки перед добавлением ограничения null
. Руководство по миграции рекомендует использовать локальную модель, например:
Рельсы 4 и выше:
class AddDivisionIdToProfile < ActiveRecord::Migration
class Profile < ActiveRecord::Base
end
def change
add_column :profiles, :division_id, :integer
Profile.reset_column_information
reversible do |dir|
dir.up { Profile.update_all division_id: Division.first.id }
end
change_column :profiles, :division_id, :integer, :null => false
end
end
Рельсы 3
class AddDivisionIdToProfile < ActiveRecord::Migration
class Profile < ActiveRecord::Base
end
def change
add_column :profiles, :division_id, :integer
Profile.reset_column_information
Profile.all.each do |profile|
profile.update_attributes!(:division_id => Division.first.id)
end
change_column :profiles, :division_id, :integer, :null => false
end
end