我有一个使用Rails应用程序创建的本地PostgreSQL数据库。它有600k的记录,其中约200k是重复的。我想只保留1条记录并删除重复项。我每天都会写SQL来工作,但Rails是我的爱好,我仍然在与ActiveRecord斗争。
以下是我找到重复项的方法(在Rails控制台中):
Summary.select(:map_id).group(:map_id).having("count(*) > 1")
我不认为我可以简单地将destroy_all
添加到该语句的末尾,因为它会销毁该条目的所有实例,包括重复值。
你能告诉我如何更新它以便删除重复项吗?
答案 0 :(得分:2)
我会转到数据库控制台(rails dbconsole
)并执行:
SELECT DISTINCT ON (map_id) * FROM summaries AS some_temp_name;
然后重命名表格。
编辑 - 这看起来像你正在寻找的东西:
Summary.where.not(id: Summary.group(:map_id).pluck('min(summaries.id)')).delete_all
未经测试。这是这个答案的一部分: Rails: Delete duplicate records based on multiple columns
答案 1 :(得分:2)
这会破坏wave中的重复项,每次传递时每map_id
只选择一个副本。当不再存在重复时,循环将自动完成。
loop do
duplicates = Summary.select("MAX(id) as id, map_id").group(:map_id).having("count(*) > 1")
break if duplicates.length == 0
duplicates.destroy_all
end
如果数据库如下所示:
| id | map_id |
| 1 | 235 |
| 2 | 299 |
| 3 | 324 |
| 4 | 235 |
| 5 | 235 |
| 6 | 299 |
| 7 | 235 |
| 8 | 324 |
| 9 | 299 |
在第一波中,这些记录将被退回并销毁:
| id | map_id |
| 7 | 235 |
| 8 | 324 |
| 9 | 299 |
在第二波中,此记录将被返回并销毁:
| id | map_id |
| 5 | 235 |
| 6 | 299 |
第三波将返回并销毁此记录:
| id | map_id |
| 4 | 235 |
第四次浪潮将完成整个过程。除非给定的map_id
有很多重复项,否则这个过程很可能会以一位数的循环迭代完成。
根据该方法,只返回重复项,并且只删除较新的重复项。要删除较旧的重复项,请将查询更改为:
duplicates = Summary.select("MIN(id) as id, map_id").group(:map_id).having("count(*) > 1")
在这种情况下,wave 1将返回并销毁:
| id | map_id |
| 1 | 235 |
| 2 | 299 |
| 3 | 324 |
第2波将返回并摧毁:
| id | map_id |
| 4 | 235 |
| 6 | 299 |
Wave 3将返回并销毁:
| id | map_id |
| 5 | 235 |
Wave 4将完成整个过程。
答案 2 :(得分:1)
我建议做的是通过具有重复项的字段获取所有记录和订单。
然后循环所有记录,每个值保留一条记录。
value = nil
Summary.order("map_id ASC").each do |record|
if record.map_id == value
# duplicate
record.destroy
else
# first entry
value = record.map_id
end
end