Подтвердить что ты не робот

Возвращает путь к reset семя в поле id

Я нашел ответы "чистого SQL" на этот вопрос. Есть ли способ в Rails, чтобы reset поле id для конкретной таблицы?
Почему я хочу это сделать? Потому что у меня есть таблицы с постоянно движущимися данными - редко более 100 строк, но всегда разные. Сейчас это до 25 тыс., И в этом просто нет смысла. Я намерен использовать планировщик, встроенный в приложение Rails (rufus-scheduler) для запуска поля id reset ежемесячно или около того.

4b9b3361

Ответ 1

Я вышел с решением, основанным на ответе hgimenez, и этот другой.

Так как я обычно работаю с Sqlite или PostgreSQL, я только для них разработал; но расширение его до, скажем, MySQL, не должно быть слишком сложным.

Поместите это внутри lib/и потребуйте его на инициализаторе:

# lib/active_record/add_reset_pk_sequence_to_base.rb
module ActiveRecord
  class Base
    def self.reset_pk_sequence
      case ActiveRecord::Base.connection.adapter_name
      when 'SQLite'
        new_max = maximum(primary_key) || 0
        update_seq_sql = "update sqlite_sequence set seq = #{new_max} where name = '#{table_name}';"
        ActiveRecord::Base.connection.execute(update_seq_sql)
      when 'PostgreSQL'
        ActiveRecord::Base.connection.reset_pk_sequence!(table_name)
      else
        raise "Task not implemented for this DB adapter"
      end
    end     
  end
end

Использование:

Client.count # 10
Client.destroy_all
Client.reset_pk_sequence
Client.create(:name => 'Peter') # this client will have id=1

EDIT: поскольку самый обычный случай, когда вы захотите сделать это, - это очистить таблицу базы данных, я рекомендую взглянуть на database_cleaner. Он автоматически выполняет сброс идентификатора. Вы можете сказать, что он удаляет только выбранные таблицы следующим образом:

DatabaseCleaner.clean_with(:truncation, :only => %w[clients employees])

Ответ 2

Вы никогда не говорили о том, какую СУБД вы используете. Если это postgreSQL, адаптер postgres ActiveRecord имеет метод reset_pk_sequences!, который вы можете использовать:

ActiveRecord::Base.connection.reset_pk_sequence!('table_name')

Ответ 3

Я предполагаю, что вам не нужны данные:

def self.truncate!
  connection.execute("truncate table #{quoted_table_name}")
end

Или если вы это сделаете, но не слишком много (есть фрагмент времени, когда данные существуют только в памяти):

def self.truncate_preserving_data!
  data = all.map(&:clone).each{|r| raise "Record would not be able to be saved" unless r.valid? }
  connection.execute("truncate table #{quoted_table_name}")
  data.each(&:save)
end

Это даст новые записи с теми же атрибутами, но id начинается с 1.

Ничего belongs_to в этой таблице не получится.

Ответ 4

Одна из проблем заключается в том, что эти типы полей реализуются по-разному для разных последовательностей баз данных, автоматических приращений и т.д.

Вы всегда можете удалить и снова добавить таблицу.

Ответ 5

Нет ничего такого в Rails. Если вам нужны хорошие идентификаторы, чтобы показать пользователям, сохраните их в отдельной таблице и повторно используйте их.

Ответ 6

Вы можете сделать это только в рельсах, если _ids устанавливаются рельсами. Пока _ids устанавливаются вашей базой данных, вы не сможете контролировать их без использования SQL.

Боковое замечание: я предполагаю, что использование рельсов для регулярного вызова процедуры SQL, которая сбрасывает или уменьшает и воссоздает последовательность, не будет чисто SQL-решением, но я не думаю, что это то, о чем вы просите...

EDIT:

Отказ от ответственности: я мало знаю о рельсах.

С точки зрения SQL, если у вас есть таблица с столбцами id first_name last_name, и вы обычно insert into table (first_name, last_name) values ('bob', 'smith'), вы можете просто изменить свои запросы на insert into table (id, first_name, last_name) values ([variable set by rails], 'bob', 'smith') Таким образом, _id устанавливается переменной, а не автоматически устанавливается по SQL. В этот момент рельсы имеют полный контроль над тем, что означает _ids (хотя, если это ПК, вам нужно убедиться, что вы не используете то же значение, пока оно еще там).

Если вы собираетесь оставить назначение до базы данных, вы должны запустить рельсы (по какому-либо расписанию):

DROP SEQUENCE MY_SEQ;
CREATE SEQUENCE MY_SEQ START WITH 1 INCREMENT BY 1 MINVALUE 1;

для любой последовательности, управляющей идентификаторами для вашей таблицы. Это избавится от текущей последовательности и создаст новую. Это самый простой способ, которым я знаю вас "reset" последовательность.

Ответ 7

Основываясь на ответе @hgmnz, я сделал этот метод, который установит последовательность в любое значение, которое вам нравится... (Проверяется только с помощью адаптера Postgres.)

# change the database sequence to force the next record to have a given id
def set_next_id table_name, next_id
  connection = ActiveRecord::Base.connection
  def connection.set_next_id table, next_id
    pk, sequence = pk_and_sequence_for(table)
    quoted_sequence = quote_table_name(sequence)
    select_value <<-end_sql, 'SCHEMA'
      SELECT setval('#{quoted_sequence}', #{next_id}, false)
    end_sql
  end
  connection.set_next_id(table_name, next_id)
end

Ответ 8

Релейный способ для, например, MySQL, но потерял все данные в таблице users:

ActiveRecord::Base.connection.execute('TRUNCATE TABLE users;')

Может быть, помогает кому-то;)