Rails способ сбросить семя на поле id - PullRequest
40 голосов
/ 20 января 2010

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

Ответы [ 9 ]

120 голосов
/ 20 января 2010

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

ActiveRecord::Base.connection.reset_pk_sequence!('table_name')
55 голосов
/ 19 октября 2011

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

Поскольку я обычно работаю с 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

РЕДАКТИРОВАТЬ: Поскольку наиболее распространенный случай, когда вы захотите сделать это, после очистки таблицы базы данных, я рекомендую взглянуть на database_cleaner . Он обрабатывает сброс идентификатора автоматически. Вы можете сказать, чтобы удалить только выбранные таблицы, как это:

DatabaseCleaner.clean_with(:truncation, :only => %w[clients employees])
5 голосов
/ 20 января 2010

Полагаю, вам нет дела до данных:

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 в этой таблице может привести в замешательство.

3 голосов
/ 18 сентября 2014

Основываясь на ответе @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
1 голос
/ 20 января 2010

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

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

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. На этом этапе rails полностью контролирует, что такое _ids (хотя, если это PK, вам нужно убедиться, что вы не используете то же значение, пока оно еще там).

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

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

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

1 голос
/ 20 января 2010

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

1 голос
/ 20 января 2010

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

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

0 голосов
/ 22 июня 2018

Существуют методы CounterCache:
https://www.rubydoc.info/docs/rails/4.1.7/ActiveRecord/CounterCache/ClassMethods
Я использовал Article.reset_counters Article.all.length - 1, и, похоже, это сработало.

0 голосов
/ 13 января 2017

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

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

Может, кому-то поможет;)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...