6

I had to migrate from a mySql based ruby on rails app to using postgresql. No problems but one so far, and I don't know how to solve it.

The migration of data brought ids along with it, and postgresql is now having problems with existing ids: it's not clear to me where it gets the value that it uses to determine the base for nextval: it certainly isn't the highest value in the column, although you might think that would be a good idea. In any case, it's now colliding with existing id values. id column, created from a standard RoR migration is defined as

not null default nextval('geopoints_id_seq'::regclass)

Is there some place that the value it uses as a base can be hacked? This problem could now arise in any of 20 or so tables: I could use

'select max(id) from <table_name>' 

but that seems to make the idea of an autoincrement column pointless.

How is this best handled?

4

5 回答 5

11

Postgres 适配器上有一个reset_pk_sequences!方法。你可以调用它,它会将它设置为 max(id) + 1,这可能是你想要的。

在某些项目中,我得到的数据 ETL 经常足以保证一个 rake 任务为所有模型或指定模型执行此操作。这是任务 - 将它包含在一些 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通过传入类名为特定模型运行它。

于 2009-11-10T18:22:38.193 回答
5

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

于 2011-04-08T00:05:42.880 回答
3

使用该定义,该列将从 geopoints_id_seq 序列中获取下一个值。该序列不直接附加到表。如果要迁移数据,则必须创建或更新该序列,使其起点大于表中当前的最大 id。

您应该能够使用例如设置其新值

   ALTER SEQUENCE geopoints_id_seq RESTART with 1692;

或者从 table_name 中选择 max(id);产量

于 2009-11-10T17:37:12.397 回答
1

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

于 2009-11-10T17:33:41.953 回答
0

使用setval()设置序列的起始值。

于 2009-11-10T17:35:23.353 回答