2016-05-18 10 views
0

私はUserモデルとLocation Modelを持っています。各ユーザは、ロケーションモデルの特定の場所に属します。複数の場所の代わりに特定の場所にすべてのユーザーを誘導し、重複を削除するためのrubyコード

ロケーションテーブルに重複した場所があります。 とユーザーが所在地に属しています。 どのように私は場所テーブル内の重複する行を削除し、1つの行を保持し、すべてのユーザーがその単一の行に属しているルビーを使用することができます。どちらのテーブルもlocation_ID属性で接続されています。

私は、移行を介してこれを実行しようとしました:

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? 
     first_one = dup_rows.shift #stored the first one 
     dup_rows.each{ |double| double.destroy } # duplicates can now be destroyed 
    } 
    end 

しかし、実行するための移行をさせない、ユーザーの外部キー制約があります。どうすればこれを達成できますか?

User 
user_id name location_id 
1   tim  1 
2   adam 2 
3   Joy  3 

Location 
location_id name 
1   NewYork 
2   NewYork 
3   NewYork 

Expected Ouput:

User 
user_id name location_id 
1   tim  1 
2   adam 1 
3   Joy  1 

Location 
location_id name 
1   NewYork 
+0

あなたのクエリから期待される出力を示してもらえますか? –

+0

最初のインスタンスまたは最後のインスタンスを保持する場合は重要ですか? 'user_id'と' location'に基づいて一意性だけを気にしますか? –

+0

私は自分の質問を編集しました。それを参照してください。私は重複を削除し、同じ場所を持つユーザーがLocationテーブルの1つのレコードだけを指し示すようにしたい。私はルビーを使用してこれを達成したいと考えています – Abhishek

答えて

0

ねえ、あなたがこの方法を試すことができます:

現行モデルである

1)最初の更新

User.joins(:location).update_all("location_id = select id from locations as l2 where l2.name = locations.name limit 1") 
を使用してロケーションテーブル内の位置の最初のエントリを持つすべてのエントリ

注:ordeサブクエリがテーブルから最初のエントリを返さない場合は、ここでidをrにします。これは、すべてのデータが正しく繰り返した場所の最初のIDが更新またはされていないことを意味ロケーションテーブルの最初のエントリで更新されますことを確認する前に

2)は、最初のエントリー・

除くロケーションテーブルからすべてのエントリを破壊します。削除後にデータを再度復元することはできないためです。その後、ちょうど

Location.where("id not in (?)", Location.select("min(id) as id").group("name").map(&:id)).destroy_all 
+0

@Abhishek私はあなたのテーブル構造と以前の質問に基づいて解決策をあなたに与えました。マイグレーションの中で何をしようとしているのですか? –

+0

マイ・マイグレーションを通して、私はロケーション・テーブルに重複した名前を持つすべての重複したロケーションを削除し、最初のものを残したいと思います。次に、その場所に所属するすべてのユーザーが、重複を削除した後に保持されているユーザーを指し示すようにしたい。私は以前に表現することができませんでした。まだ明確でない場合は教えてください。私は2日以来これに固執しています:/ – Abhishek

+0

@Abhishekあなたは私の応答を試みましたか?私はSQLクエリと同じことをしているので、 –

0

ちょっと醜いを使用して最初の項目を除く、すべての繰り返しエントリを破壊していますが、サブクエリを使用することができます:

まず、重複しているすべてのレコードの最初の発生をつかむと、

original_duplicate_locations = Location.select("MIN(id) AS id, name, user_id").group(:name, :user_id).having("COUNT(id) > 1") 

余分な重複が同じid同じnameを持つ場所として定義され、user_idれていませんが:

duplicates_not_including_originals = Location.joins("JOIN (#{duplicates.to_sql}) dupes ON locations.name = dupes.name AND locations.user_id = dupes.user_id AND locations.id <> dupes.id") 
関連する問題