여러 열을 기반으로 중복 레코드를 제거 하시겠습니까?
저는 Heroku를 사용하여 Ruby on Rails 애플리케이션을 호스팅하고 있으며 어떤 이유로 든 중복 된 행이있을 수 있습니다.
2 개 이상의 기준에 따라 중복 레코드를 삭제하지만 해당 중복 컬렉션의 레코드는 1 개만 유지하는 방법이 있습니까?
제 사용 사례에서는 데이터베이스에 자동차에 대한 제조사 및 모델 관계가 있습니다.
Make Model
--- ---
Name Name
Year
Trim
MakeId
이름, 연도 및 트림이 동일하지만 해당 레코드 중 하나를 유지하는 모든 모델 레코드를 삭제하고 싶습니다 (즉, 레코드가 필요하지만 한 번만 필요함). 일부 활성 레코드 쿼리를 쉽게 실행할 수 있도록 Heroku 콘솔을 사용하고 있습니다.
어떤 제안?
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
- 모두 찾기
- 고유성을 위해 필요한 키로 그룹화
- 그룹화 된 모델의 해시 값에 대한 루프
- 하나의 사본을 유지하기 위해 첫 번째 값을 제거하십시오
- 나머지는 삭제
사용자 테이블 데이터가 아래와 같은 경우
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 단계:
모든 고유 이메일 레코드 ID를 얻으려면.
ids = User.select("MIN(id) as id").group(:email,:name).collect(&:id)
=> [15, 16, 18, 19, 17]
2 단계:
고유 한 이메일 레코드 ID가있는 사용자 테이블에서 중복 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
** 레일 4 **
ActiveRecord 4는 .not
2 단계에서 다음을 작성할 수 있는 방법을 소개합니다 .
User.where.not(id: ids).destroy_all
@Aditya Sanghi의 답변과 비슷하지만 모든 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'
다음을 시도해 볼 수 있습니다. (이전 답변을 기반으로)
ids = Model.group('name, year, trim').pluck('MIN(id)')
모든 유효한 기록을 얻으려면. 그리고:
Model.where.not(id: ids).destroy_all
to remove the unneeded records. And certainly, you can make a migration that adds a unique index for the three columns so this is enforced at the DB level:
add_index :models, [:name, :year, :trim], unique: true
To run it on a migration I ended up doing like the following (based on the answer above by @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
You can try this sql query, to remove all duplicate records but latest one
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);
참고URL : https://stackoverflow.com/questions/14124212/remove-duplicate-records-based-on-multiple-columns
'Program Tip' 카테고리의 다른 글
Facebook의 소셜 플러그인에 유동 폭을 설정할 수 있습니까? (0) | 2020.10.25 |
---|---|
부트 스트랩을 위해 팝 오버에 닫기 버튼을 삽입하는 방법 (0) | 2020.10.25 |
속성 이름을 문자열로 사용하여 속성별로 정렬하는 코드 (0) | 2020.10.25 |
EditText가 대문자로 텍스트를 시작하도록 강제하는 방법은 무엇입니까? (0) | 2020.10.25 |
핀치를 감지하는 가장 간단한 방법 (0) | 2020.10.25 |