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

https://gist.github.com/909032


С этим определением столбец получит следующее значение из последовательности 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() установить начальное значение для последовательности.