postgresql nextval генерирует существующие значения
Мне пришлось перейти от приложения ruby on rails на основе mySql к использованию postgresql. Пока никаких проблем, но я не знаю, как их решить.
Миграция данных принесла с собой идентификаторы, и у postgresql теперь есть проблемы с существующими идентификаторами: мне не ясно, где он получает значение, которое он использует для определения базы для следующего значения: это, конечно, не самое высокое значение в колонка, хотя вы можете подумать, что это будет хорошая идея. В любом случае, теперь он сталкивается с существующими значениями идентификатора. Столбец id, созданный из стандартной миграции RoR, определяется как
not null default nextval('geopoints_id_seq'::regclass)
Есть ли место, где значение, которое оно использует в качестве основы, можно взломать? Эта проблема теперь может возникнуть в любой из 20 или около того таблиц: я мог бы использовать
'select max(id) from <table_name>'
но это, кажется, делает идею колонки автоинкремента бессмысленной.
Как это лучше всего обрабатывается?
5 ответов
E сть reset_pk_sequences!
метод на адаптере Postgres. Вы можете вызвать его, и он установит его в max(id) + 1, что, вероятно, то, что вы хотите.
В некоторых проектах я получаю данные ETL достаточно часто, чтобы оправдать выполнение граблей для всех моделей или для конкретной модели. Вот задача - включить ее в какой-нибудь Rakefile или в свой собственный в lib/tasks:
desc "Reset all sequences. Run after data imports"
task :reset_sequences, :model_class, :needs => :environment do |t, args|
if args[:model_class]
classes = Array(eval args[:model_class])
else
puts "using all defined active_record models"
classes = []
Dir.glob(RAILS_ROOT + '/app/models/**/*.rb').each { |file| require file }
Object.subclasses_of(ActiveRecord::Base).select { |c|
c.base_class == c}.sort_by(&:name).each do |klass|
classes << klass
end
end
classes.each do |klass|
next if klass == CGI::Session::ActiveRecordStore::Session && ActionController::Base.session_store.to_s !~ /ActiveRecordStore/
puts "reseting sequence on #{klass.table_name}"
ActiveRecord::Base.connection.reset_pk_sequence!(klass.table_name)
end
end
Теперь вы можете запустить это либо для всех моделей (определенных в RAIS_ROOT/app/models), используя rake reset_sequences
или для конкретной модели, передавая имя класса.
Версия рельсов 3 выглядит так:
namespace :db do
desc "Reset all sequences. Run after data imports"
task :reset_sequences, :model_class, :needs => :environment do |t, args|
if args[:model_class]
classes = Array(eval args[:model_class])
else
puts "using all defined active_record models"
classes = []
Dir.glob(RAILS_ROOT + '/app/models/**/*.rb').each { |file| require file }
ActiveRecord::Base.subclasses.select { |c|c.base_class == c}.sort_by(&:name).each do |klass|
classes << klass
end
end
classes.each do |klass|
puts "reseting sequence on #{klass.table_name}"
ActiveRecord::Base.connection.reset_pk_sequence!(klass.table_name)
end
end
end
С этим определением столбец получит следующее значение из последовательности geopoints_id_seq. Эта последовательность непосредственно не привязана к таблице. Если вы переносите данные, вы должны создать или обновить эту последовательность, чтобы ее начальная точка была больше, чем текущий максимальный идентификатор в вашей таблице.
Вы должны быть в состоянии установить его новое значение с помощью, например,
ALTER SEQUENCE geopoints_id_seq RESTART with 1692;
Или как выбрать max(id) из table_name; доходность
PG использует последовательности:
Сделайте так, чтобы его текущее значение было на 1 больше, чем самое высокое значение в вашей таблице.
SELECT setval('geopoints_id_seq', 999999999, true);
Также посмотрите эти
http://www.postgresql.org/docs/8.4/interactive/datatype-numeric.html
http://www.postgresql.org/docs/8.4/interactive/functions-sequence.html
Используйте setval(), чтобы установить начальное значение для последовательности.