mysql - 删除由多个属性唯一标识的重复记录/对象

标签 mysql ruby-on-rails ruby validation activerecord

我有一个名为 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。哪一个?日期最近的那个。

我有三个问题:

  1. 如何使用纯 SQL 方法删除重复项?

  2. 如何使用纯 Ruby 解决方案删除重复项?类似于此:Removing "duplicate objects" .

  3. 如何进行验证以防止将来重复输入?

最佳答案

对于仅使用 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/

相关文章:

ruby-on-rails - rails : Securing route to customer to prevent unauthorized access

javascript - 如何使用 Ruby 抓取由 Javascript 函数生成的数据?

mysql - 使用 LOCATE 和 SUBSTRING 从 MySQL 返回特定文本

php - 为什么 DateTime() 在 Laravel 中不起作用?

ruby-on-rails - Ruby on Rails 6 + Docker = Webpacker::Manifest::MissingEntryError?

ruby-on-rails - 为什么 Gem 在 RubyGems 中提供 ~> AND =>?

c - mongodb 作为循环数据库

ruby-on-rails - 如何创建/维护对 ActiveRecord 关联中特定对象的有效引用?

php - SimpleXML 问题,将项目列表包装在一个 <tag> 中

mysql - 搜索并替换部分字符串