2009-11-10 15 views
6

Musiałem migrować z ruby ​​mySql opartej na aplikacji railsowej do używania postgresql. Żadnych problemów, ale jak dotąd, i nie wiem, jak to rozwiązać.Następujące generowanie wartości postgresql

Migracja danych przyniosła id wraz z nim, a postgresql ma teraz problemy z istniejącymi identyfikatorami: nie jest dla mnie jasne, skąd otrzymuje wartość, którą wykorzystuje do określenia podstawy dla nextval: to na pewno nie jest najwyższa wartość w kolumnie, chociaż możesz pomyśleć, że byłby to dobry pomysł. W każdym razie teraz koliduje z istniejącymi wartościami id. kolumna id, stworzony ze standardowego migracji RoR jest zdefiniowany jako

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

Czy jest jakieś miejsce, że wartość wykorzystuje jako bazę można hacked? Ten problem może pojawić się w każdym z 20 lub tabelach: Mogłem użyć

'select max(id) from <table_name>' 

ale wydaje się, aby ideę kolumny autoIncrement bezcelowe.

W jaki sposób najlepiej sobie z tym radzić?

Odpowiedz

11

Istnieje metoda reset_pk_sequences! na Postgres adapter. Możesz zadzwonić i ustawi to na max (id) + 1, co prawdopodobnie jest tym, czego potrzebujesz.

W niektórych projektach otrzymuję dane ETL na tyle często, że gwarantują wykonanie zadania rake dla wszystkich modeli lub dla określonego modelu. Oto zadanie - umieścić go w jakimś Rakefile lub w jego własnej pod lib/zadań:

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 

Teraz można uruchomić to albo dla wszystkich modeli (określonych w RAIS_ROOT/app/models) stosując rake reset_sequences, lub dla określonego model poprzez podanie nazwy klasy.

+0

Wow, dzięki za szybką i przydatnych odpowiedzi wszystkich. Zajmę się uruchomieniem rozwiązania @hgimenez, ponieważ jestem w środowisku Rails, ale domyślam się, że mogę to zrobić za pomocą linii poleceń w postgresie. W następstwie: Mam zamiar spróbować, ale czy mogę umieścić takie oświadczenie w migracji –

+0

Zdecydowanie, możesz mieć migrację, która idzie: ActiveRecord :: Base.connection.reset_pk_sequence! ('Table_name'), ale można to oczywiście zrobić również z psql. – hgmnz

+0

+1 punkt za awesomenessa – kikito

0

Zastosowanie setval() do ustawiania wartości początkowej dla tej sekwencji.

3

z tą definicją kolumna otrzyma następną wartość z sekwencji geopoints_id_seq. Ta sekwencja nie jest bezpośrednio dołączona do tabeli. Jeśli przenosisz dane, musisz utworzyć lub zaktualizować tę sekwencję, aby jej punkt początkowy był większy niż bieżący maksymalny identyfikator w tabeli.

Powinieneś mieć możliwość ustawienia nowej wartości przez np.

ALTER SEQUENCE geopoints_id_seq RESTART with 1692; 

Lub cokolwiek wybierz max (id) od table_name; wydajność:

5

Szyny 3 wersja wygląda tak:

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

+2

Myślę, że 'RAILS_ROOT' powinno być zamiast' Rails.root.to_s'. Ponadto składnia 'task' jest przestarzała. Myślę, że powinno to być 'task: reset_sequences, [: model_class] => [: environment]' –

Powiązane problemy