すでにレコードが入っているテーブルに後からユニーク制約を追加したいとき、すでに重複したレコードが含まれているとユニーク制約が追加できません。
そこでRailsのActiveRecordで、重複したレコードを一つだけ残して、残りを削除するスクリプトを書きました。以下は、articlesテーブルのtitle・media・user_idカラムに、複合ユニーク制約をつけたいケースです。
# 重複したデータを取得する
sql = 'SELECT title, media, user_id FROM articles GROUP BY title, media, user_id HAVING COUNT(*) > 1;'
# 重複したレコードのIDを取得して、一つだけ残す
duplicates = Article.find_by_sql(sql)
duplicate_ids = duplicates.inject([]) do |duplicate_ids, dup|
articles = Article.select(:id).where(title: dup.title, media: dup.media, user_id: dup.user_id)
duplicate_ids << articles.pluck(:id)[1..-1]
end
# 重複したレコードのIDを削除する
Article.where(id: duplicate_ids.flatten).destroy_all