我有一个名为 HeroStatus 的模型,它具有以下属性:
- 编号
- 用户编号
- 可记录类型
- hero_type(可以为 NULL!)
- recordable_id
- 创建于
有超过 100 个 hero_statuses,一个用户可以有多个 hero_statuses,但不能多次拥有相同的 hero_status。
用户的 hero_status 由 recordable_type + hero_type + recordable_id 的组合唯一标识。我基本上想说的是,特定用户不能有重复的 hero_status。
不幸的是,我没有适当的验证来确保这一点,所以在我做了一些代码更改后,我为用户获得了一些重复的 hero_statuses。例如:
user_id = 18
recordable_type = 'Evil'
hero_type = 'Halitosis'
recordable_id = 1
created_at = '2010-05-03 18:30:30'
user_id = 18
recordable_type = 'Evil'
hero_type = 'Halitosis'
recordable_id = 1
created_at = '2009-03-03 15:30:00'
user_id = 18
recordable_type = 'Good'
hero_type = 'Hugs'
recordable_id = 1
created_at = '2009-02-03 12:30:00'
user_id = 18
recordable_type = 'Good'
hero_type = NULL
recordable_id = 2
created_at = '2009-012-03 08:30:00'
(最后两个显然不是重复。前两个是。)所以我想做的是摆脱重复的 hero_status。哪一个?日期最近的那个。
我有三个问题:
如何使用纯 SQL 方法删除重复项?
如何使用纯 Ruby 解决方案删除重复项?类似于此:Removing "duplicate objects" .
如何进行验证以防止将来重复输入?
最佳答案
对于仅使用 SQL 的方法,我将使用此查询 -(我假设 ID 是唯一的。)
DELETE FROM HeroStatus WHERE id IN
(SELECT id FROM
(SELECT user_id, recordable_type, hero_type, recordable_id, MAX(created_at)
GROUP BY del.user_id, recordable_type, hero_type, recordable_id
HAVING Count(id)>1) AS del
INNER JOIN HeroStatus AS hs ON
hs.user_id=del.user_id AND hs.recordable_type=del.recordable_type
AND hs.hero_type=del.hero_type AND hs.recordable_id=del.recordable_id
AND hs.created_at = del.created_at)
有点怪!该查询使用自然键(user_id、recordable_type、hero_type)查找所有重复项,并选择具有最大 created_at
值(最近创建)的那个。然后找到这些行的 ID(通过连接回主表)并删除具有该 ID 的行。
(请先在表格的副本上尝试此操作,并验证您是否获得了想要的结果!:-)
为防止将来发生这种情况,请在列 user_id、recordable_type、hero_type、recordable_id 上添加唯一索引或约束。例如
ALTER TABLE HeroStatus
ADD UNIQUE (user_id, recordable_type, hero_type, recordable_id)
编辑:
您在这样的迁移中添加(和删除)此索引:
add_index(:HeroStatus, [:user_id, :recordable_type, :hero_type, :recordable_id], :unique => true)
remove_index(:HeroStatus, :column => [:user_id, :recordable_type, :hero_type, :recordable_id], :unique => true)
或者,如果您想明确命名它:
add_index(:HeroStatus, [:user_id, :recordable_type, :hero_type, :recordable_id], :unique => true, :name => :my_unique_index)
remove_index(:HeroStatus, :name => :my_unique_index)
关于mysql - 删除由多个属性唯一标识的重复记录/对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2791397/