我找到了这个问题的“纯SQL”答案。是否有一种方法, 在Rails ,重置特定表的id字段?
我为什么要这样做?因为我有不断移动数据的表 - 很少超过100行,但总是不同。它现在高达25k,而且没有任何意义。我打算使用Rails应用程序内部的调度程序(rufus-scheduler)来每月运行id字段重置。
答案 0 :(得分:120)
您从未提及您正在使用的DBMS。如果这是postgreSQL,ActiveRecord postgres适配器有一个reset_pk_sequences!
方法可以使用:
ActiveRecord::Base.connection.reset_pk_sequence!('table_name')
答案 1 :(得分:55)
我根据hgimenez的回答和this other one提出了解决方案。
因为我经常使用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。它自动处理ID重置。你可以告诉它只删除这样的选定表:
DatabaseCleaner.clean_with(:truncation, :only => %w[clients employees])
答案 2 :(得分:5)
我假设您不关心数据:
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 :(得分:3)
基于@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
答案 4 :(得分:1)
一个问题是,对于不同的数据库序列,自动增量等,这些字段的实现方式不同。
您可以随时删除并重新添加表格。
答案 5 :(得分:1)
Rails中没有这样的东西。如果您需要一个漂亮的ID来显示用户,那么将它们存储在一个单独的表中并重复使用它们。
答案 6 :(得分:1)
如果由rails设置了_ids,则只能在rails 中执行 。只要数据库设置了_ids,就不能在不使用SQL的情况下控制它们。
旁注:我想使用rails来定期调用重置或删除的SQL过程并重新创建序列不会是纯粹的SQL解决方案,但我不认为这就是你所要求的...... < / p>
编辑:
免责声明:我对rails不太了解。
从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,你需要确保在它仍在那里时不要使用相同的值)。
如果要将作业保留到数据库中,则必须运行rails(在任何时间表上):
DROP SEQUENCE MY_SEQ;
CREATE SEQUENCE MY_SEQ START WITH 1 INCREMENT BY 1 MINVALUE 1;
以任何顺序控制表的ID。这将摆脱当前序列,并创建一个新序列。这是我知道你“重置”序列的最简单方法。
答案 7 :(得分:0)
Rails方式,例如MySQL,但丢失了表users
中的所有数据:
ActiveRecord::Base.connection.execute('TRUNCATE TABLE users;')
也许可以帮助别人;)
答案 8 :(得分:0)
有CounterCache方法:
https://www.rubydoc.info/docs/rails/4.1.7/ActiveRecord/CounterCache/ClassMethods
我使用了times(2)
,它似乎可以正常工作。