删除基于多列的重复logging?

我使用Heroku托pipe我的Ruby on Rails应用程序,出于某种原因,我可能有一些重复的行。

有没有办法删除重复的logging基于2个或更多的标准,但只保留1重复的集合logging?

在我的使用案例中,我在数据库中有一个汽车制造和模型关系。

Make Model --- --- Name Name Year Trim MakeId 

我想要删除所有具有相同名称,年份和修剪的模型logging,但保留其中的一个logging(意思是,我需要logging,但只有一次)。 我正在使用Heroku控制台,所以我可以轻松地运行一些活动的logging查询。

有什么build议么?

 class Model def self.dedupe # find all models and group them on keys which should be common grouped = all.group_by{|model| [model.name,model.year,model.trim,model.make_id] } grouped.values.each do |duplicates| # the first one we want to keep right? first_one = duplicates.shift # or pop for last one # if there are any more left, they are duplicates # so delete all of them duplicates.each{|double| double.destroy} # duplicates can now be destroyed end end end Model.dedupe 
  • find所有
  • 将它们分组在您需要唯一性的键上
  • 循环分组模型的哈希值
  • 删除第一个值,因为你想保留一个副本
  • 删除其余的

如果你的用户表数据如下

 User.all => [ #<User id: 15, name: "a", email: "a@gmail.com", created_at: "2013-08-06 08:57:09", updated_at: "2013-08-06 08:57:09">, #<User id: 16, name: "a1", email: "a@gmail.com", created_at: "2013-08-06 08:57:20", updated_at: "2013-08-06 08:57:20">, #<User id: 17, name: "b", email: "b@gmail.com", created_at: "2013-08-06 08:57:28", updated_at: "2013-08-06 08:57:28">, #<User id: 18, name: "b1", email: "b1@gmail.com", created_at: "2013-08-06 08:57:35", updated_at: "2013-08-06 08:57:35">, #<User id: 19, name: "b11", email: "b1@gmail.com", created_at: "2013-08-06 09:01:30", updated_at: "2013-08-06 09:01:30">, #<User id: 20, name: "b11", email: "b1@gmail.com", created_at: "2013-08-06 09:07:58", updated_at: "2013-08-06 09:07:58">] 1.9.2p290 :099 > 

电子邮件ID是重复的,所以我们的目标是从用户表中删除所有重复的电子邮件ID。

步骤1:

获取所有不同的电子邮件loggingID。

 ids = User.select("MIN(id) as id").group(:email,:name).collect(&:id) => [15, 16, 18, 19, 17] 

第2步:

使用不同的电子邮件loggingID从用户表中删除重复的ID。

现在,ids数组包含以下ID。

 [15, 16, 18, 19, 17] User.where("id NOT IN (?)",ids) # To get all duplicate records User.where("id NOT IN (?)",ids).destroy_all 

** RAILS 4 **

ActiveRecord 4引入了.not方法,它允许你在步骤2中编写以下内容:

 User.where.not(id: ids).destroy_all 

与@Aditya Sanghi的答案类似,但是这种方式会更高效,因为您只select重复项,而不是将每个Model对象加载到内存中,然后遍历所有对象。

 # returns only duplicates in the form of [[name1, year1, trim1], [name2, year2, trim2],...] duplicate_row_values = Model.select('name, year, trim, count(*)').group('name, year, trim').having('count(*) > 1').pluck(:name, :year, :trim) # load the duplicates and order however you wantm and then destroy all but one duplicate_row_values.each do |name, year, trim| Model.where(name: name, year: year, trim: trim).order(id: :desc)[1..-1].map(&:destroy) end 

另外,如果你真的不希望在这个表中有重复的数据,你可能想要在表中添加一个多列唯一索引,

 add_index :models, [:name, :year, :trim], unique: true, name: 'index_unique_models' 

为了在迁移中运行它,我最终完成了以下操作(根据上面的@ aditya-sanghi的答案 )

 class AddUniqueIndexToXYZ < ActiveRecord::Migration def change # delete duplicates dedupe(XYZ, 'name', 'type') add_index :xyz, [:name, :type], unique: true end def dedupe(model, *key_attrs) model.select(key_attrs).group(key_attrs).having('count(*) > 1').each { |duplicates| dup_rows = model.where(duplicates.attributes.slice(key_attrs)).to_a # the first one we want to keep right? dup_rows.shift dup_rows.each{ |double| double.destroy } # duplicates can now be destroyed } end end 

你可以试试这个sql查询,删除所有重复的logging,但最新的一个

 DELETE FROM users USING users user WHERE (users.name = user.name AND users.year = user.year AND users.trim = user.trim AND users.id < user.id);