postgresql nextval генерация существующих значений
мне пришлось перейти от приложения ruby on rails на основе mySql к использованию postgresql. Пока никаких проблем, кроме одной, и я не знаю, как ее решить.
миграция данных принесла идентификаторы вместе с ним, и postgresql теперь имеет проблемы с существующими идентификаторами: мне непонятно, где он получает значение, которое он использует для определения базы для nextval: это, конечно, не самое высокое значение в столбце, хотя вы можете подумать, что это было бы хорошей идеей. В любом случае, сейчас столкновение с существующими значениями id. столбец id, созданный из стандартной миграции RoR, определяется как
not null default nextval('geopoints_id_seq'::regclass)
есть ли место, где значение, которое он использует в качестве базы, может быть взломано? Теперь эта проблема может возникнуть в любой из 20 или около того таблиц: я мог бы использовать
'select max(id) from <table_name>'
но это, похоже, делает идею столбца автоинкремента бессмысленной.
Как это лучше решить?
5 ответов
есть reset_pk_sequences!
метод адаптер Postgres. Вы можете вызвать его, и он установит его на max (id) + 1, что, вероятно, то, что вы хотите.
в некоторых проектах я получаю данные ETL'Ed достаточно часто, чтобы гарантировать задачу рейка, чтобы сделать это для всех моделей или для указанной модели. Вот задача-включить ее в какой-нибудь 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
, или для определенной модели путем передачи имени класса.
версия rails 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#DATATYPE-SERIAL
http://www.postgresql.org/docs/8.4/interactive/functions-sequence.html
использовать setval() установить начальное значение для последовательности.