2009-03-20 13 views
4

私はID、名前、姓、生年月日、PersonalKey、個人情報、方向、ソースを繰り返したテーブルを持っています。MySQLの重複行

ここで、sourceは情報の出所を教えてくれます。

繰り返し情報には固有のIDがあり、その情報を削除する必要があります。 しかし、、私はいくつかのソース情報より優先しています。私はその情報を保持し、もう一方は消去する必要があります。

他のものは、私がいなくてもらいたいという情報がいくつかあるので、私はPersonalKeyを一杯にしておき、それを繰り返して消していく必要があります。ご覧のとおり

表はPruebas

---Id, Name, Firstname, Lastname, Birth, RFC, Source, PersonalKey--- 
---2,Juan,Garcia,Escobeddo,1983-08-04,GAED87393, DRV484930, 34233-- 
---3,Juan,Garcia,Escobedo,1987-08-04,GAED87393, FIN484930, -- 
---4,Juan,Garcia,Escobedo,1987-08-04,GAED87393, SA484930, -- 

の名前:

  • IDは一意である
  • 名、姓と名のが繰り返される
  • ID 2がPersonalKey値を持ち、 3と4はしません。
    • I 'FIN%'ソースが残っていて他のものが消去された状態にしておきたいのですが、残っている行がPersonalKey値(IOW、私はPersonalKey値を失いたくありません)を取得する必要があります。

ありがとうございます。

+0

だから、それがお役に立てば幸いFIN Sourceを削除し、FIN以外のすべてを削除しますか? –

+0

私は行がファーストネーム、姓、生年月日によってDUPであることを知っています。 CONCAT( 'FirstName、bla、bla')と完全な名前と出生によってorderyngのようなものです。しかし、私は大規模な方法で変更を行う必要があります.2百万のレジストリがあるからです。 – Granger

+0

しかし、あなたの例では2と3と4から別の姓があります。 –

答えて

3

私はこのクエリに(MySQLのSPプログラミング言語やJava、Pythonの、.NETでの)カーソルを実行します:

select Name, Firstname, Lastname, count(1) 
    from Pruebas 
group by Name, Firstname, Lastname 
having count(1) > 1 

その後、カーソルから返される行の上に、あなたがする必要があるものは何でも:FIN%インスタンスをチェックし、PersonalKeyの存在を確認し、それに応じて更新します。カーソル上の行ごとに

、あなたが別のカーソルを開くことができます。

select * 
    from Pruebas 
where Name = the_Name 
    and Firstname = the_Firstname 
    and Lastname = the_Lastname 

そして今、あなたが変更されますすべての行で、内側にカーソルを持っています。それが必要なものであれば、それを保存し、あなたが言及したKEY値でそれを更新してください。それ以外の場合は削除します。

Oracleでは、1つのクエリで必要なものを達成できましたが、この方法では同じようなパフォーマンスを得ることはできません。

希望します。

+0

すべての権利、私はいくつかのより多くのオリエンテーションが必要です..私は正しい場合、私はSP(私は知っているが、私はそれを読んでいないが、そのクエリに基づいて、私はどのIDを知っているだろう)カウントされたものが繰り返されますか?私は名前の繰り返しのバブルでどのように働くことができますか? – Granger

+0

投稿をもう一度確認してください。私はそれを少し編集した。 –

2

私はこのような何かをするだろう:

Pruebas FROM TABLE Pruebas_new
SELECT *をCREATE
GROUPの名前で、ファーストネーム、
は 'FIN%' のようなソースを持つLASTNAME。

これは、高速である必要がある場合は元のテーブルの内容を上書きしますが、必要なデータは最も簡単な方法で取得できます。

+0

私はこれを行う方法は私のPruebaデータベースのクローンを作成してPrueba2と言うことができますし、pruebaからprueba2へのクエリを実行するのですか? 質問のロジックを理解できません。申し訳ありません。 – Granger

+0

私はソースがFINを持っているテーブルを作成すると思います。その後、元のPruebaテーブルにコピーし直すことができます。 – jimiyash

3

考えられる最も簡単な解決策は、PersonalKeyを他の重複行にコピーし、'FIN%'に一致しないすべての行を削除することです。

UPDATE Pruebas p1 JOIN Pruebas p2 
ON (SOUNDEX(CONCAT(p1.Name, p2.Firstname, p3.Lastname)) 
    = SOUNDEX(CONCAT(p2.Name, p2.Firstname, p2.Lastname))) 
SET p1.PersonalKey = p2.PersonalKey 
WHERE p2.PersonalKey IS NOT NULL; 

DELETE FROM Pruebas WHERE Source NOT LIKE 'FIN%'; 

SOUNDEX()を使用して、おおよその一致表現を結合に表示しています。


私は他のコメントから、さまざまなバリエーションと不確実性を残しています。この場合、クリーンアップと重複排除を自動化する方法はありません。あるいは、少なくとも自動クリーンアップは、手動で行うよりも複雑で難しくなります。


クエリに時間がかかるというご意見をお寄せください:はい、実際は効率的ではないと思われます。 JOIN式はsargableではありません。つまり、インデックスを利用することはできません。余分な列を追加して、名前、名、姓のSOUNDEX()値を物理的に格納することで、より効率的にすることができます。次に、その列に索引を作成します。

SOUNDEX()は、とにかくすべてのスペルミスを検出するとは限りません。あなたは完全に自動化できないデータクリーンアップタスクに直面しています。 データのクリーンアップを行うには、手作業が必要です。

+0

私はビル・カーウィンさん、申し訳ありませんがあなたの答えはすばらしく見えますが、疑問があります。完全名が同音異義語の場合はどうなりますか?なぜ私が不思議に思っていたのか、名前、名字、姓、出生との比較。 ありがとうございます! – Granger

+0

私は理解していますが、場合によってはスペルミスがあります。あなたはそれらを近似式と突き合わせるための何らかの方法が必要です。 SOUNDEX()はMySQLの組み込み関数です。 –

+0

唯一の他のオプションは、名前を手動でクリーンアップすることです。次に、近似の代わりに単純な等価比較を使用できます。 –

1

回答が遅れて申し訳ありません。私はここ数日、ちょっと忙しかった。

以下

は、以下の仮定に基づいて私の答えです:

1)あなたは、いくつかの他の機構を介して名前のスペルの問題をクリーンアップされます(あなたがあなたの元にコメントで正規表現を使用してそれをクリーンアップするだろうと述べました質問)。

2)DUPセットは、Firstname、Lastname、およびBirth(元の質問のコメントにこれを記載)を使用して識別できます。

3)ファーストネーム、姓、および生年月日はNULLにすることはできません。

4)DUPセットに複数のFINレコードを含めることはできません(元の質問のコメントにこれを記載しています)。

上記のいずれかの仮定が有効でない場合は、私の答えを変更する必要があります。

次は取るべき手順は次のとおりです。

1)非FINレコードからPersonalKeyをコピーするために、すべてのFINレコードを更新します。

UPDATE Pruebas p1 
INNER JOIN Pruebas p2 
     ON p1.Firstname = p2.Firstname 
     AND p1.Lastname = p2.Lastname 
     AND p1.Birth = p2.Birth 
     SET p1.PersonalKey = p2.PersonalKey 
    WHERE p1.Source like 'FIN%' 
     AND p1.PersonalKey is null 
     AND p2.PersonalKey is not null; 

2)ここで、すべての非FINレコードを削除します。唯一FIN記録が残されているように、FIN記録を持つすべてのDUPが洗浄されています。この時点で

DELETE p2 
     FROM Pruebas p1 
INNER JOIN Pruebas p2 
     ON p1.Firstname = p2.Firstname 
     AND p1.Lastname = p2.Lastname 
     AND p1.Birth = p2.Birth 
    WHERE p1.Source like 'FIN%' 
     AND p2.Source not like 'FIN%'; 

:我々はFINレコードを持っています。

3)他のすべてのケースでDRVレコードにとどまることにした場合。我々はDRVレコードに別のレコードからPersonalKeyをコピーする必要があります。

UPDATE Pruebas p1 
INNER JOIN Pruebas p2 
     ON p1.Firstname = p2.Firstname 
     AND p1.Lastname = p2.Lastname 
     AND p1.Birth = p2.Birth 
     SET p1.PersonalKey = p2.PersonalKey 
    WHERE p1.Source like 'DRV%' 
     AND p1.PersonalKey is null 
     AND p2.PersonalKey is not null; 

4)我々はDRVレコード持っているすべての非DRVレコードの削除:この時点で、すべてのDUPを

DELETE p2 
     FROM Pruebas p1 
INNER JOIN Pruebas p2 
     ON p1.Firstname = p2.Firstname 
     AND p1.Lastname = p2.Lastname 
     AND p1.Birth = p2.Birth 
    WHERE p1.Source like 'DRV%' 
     AND p2.Source not like 'DRV%'; 

をDRVレコードが残っているように、DRVレコードが削除されました。

唯一のレコードタイプがSAレコードの場合は、それ以上DUPが残っていないので、完了です。

5)最も多くの情報が入力されたレコードを選択したい場合や、3と4を終了して複数のレコードタイプが残っていて、DUPが発生している場合。と1以外のすべてのレコードを削除します)

UPDATE Pruebas p1 
INNER JOIN Pruebas p2 
     ON p1.Firstname = p2.Firstname 
     AND p1.Lastname = p2.Lastname 
     AND p1.Birth = p2.Birth 
     SET p1.PersonalKey = p2.PersonalKey 
    WHERE p1.Source not like 'FIN%' 
     AND p1.PersonalKey is null 
     AND p2.PersonalKey is not null; 

6:我々はすべての非FINレコードのためにそれを持っていない任意のレコードにそれを持っているDUPセット内の任意のレコードからPersonalKeyをコピーする必要があります(info_score計算列で定義されている)ほとんどの情報:それは利用可能だったとFINレコードが保存された場合、彼らはそれ以外のいずれかDRVレコード存在していた場合、または

DELETE p5 
     FROM Pruebas p5 
INNER JOIN (SELECT p3.Firstname 
       , p3.Lastname 
       , p3.Birth 
       , MIN(p3.Id) AS min_id 
       FROM Pruebas p3 
     INNER JOIN (SELECT p1.Firstname 
         , p1.Lastname 
         , p1.Birth 
         , count(*) AS c 
         , MAX((p1.Name is not null) + (p1.RFC is not null) + (p1.Source is not null) + (p1.PersonalKey is not null)) AS info_score 
         FROM Pruebas p1 
        GROUP BY p1.Firstname 
         , p1.Lastname 
         , p1.Birth 
        HAVING count(*) > 1) p2 
       ON p3.Firstname = p2.Firstname 
       AND p3.Lastname = p2.Lastname 
       AND p3.Birth = p2.Birth 
       AND ((p3.Name is not null) + (p3.RFC is not null) + (p3.Source is not null) + (p3.PersonalKey is not null)) = p2.info_score 
      GROUP BY p3.Firstname 
       , p3.Lastname 
       , p3.Birth) p4 
     ON p4.Firstname = p5.Firstname 
     AND p4.Lastname = p5.Lastname 
     AND p4.Birth = p5.Birth 
     AND p4.min_id <> p5.Id; 

すべてのDUPがPersonalKeyで崩壊してきたこの時点では、保存されました最も情報の多いレコードが保存されました。

ご質問がありましたら教えてください。

は名前、ファーストネーム、姓、誕生、およびRFCが同じであれば、その後で1にDRVソースと1からPersonalKeyをコピーし、

-Dipin

+0

Bill Karwinと同じです。遅れて申し訳ありませんが、クエリから16時間が経過しました。私はあなたとまったく同じように作っていますが、まだ作業しています。クイックを大きなDBに改善する方法についてのアイデアはありますか?または、時間をチェックする方法、またはクエリが適切に行われるかどうかをチェックする方法はありますか? – Granger

+0

これはビルの答えと同じではありません。彼の回答は、そのDUPのFINレコードがなくても、すべての非FINレコードを削除します。テーブルはどれくらい大きいですか?あなたはどのインデックスを持っていますか? Where句の違いにより、私のクエリはBillより効率的です。 PS、Testで実行していることを願っています。 – Dipin