すべての重複を削除しようとしていますが、単一のレコード(短いID)のみを保持しています。次のクエリは重複を削除しますが、すべてのコピーを削除して元のコピーを維持するには、多くの反復を必要とします。
DELETE FROM emailTable WHERE id IN (
SELECT * FROM (
SELECT id FROM emailTable GROUP BY email HAVING ( COUNT(email) > 1 )
) AS q
)
そのMySQL。
編集#1 DDL
CREATE TABLE `emailTable` (
`id` mediumint(9) NOT NULL auto_increment,
`email` varchar(200) NOT NULL default '',
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=298872 DEFAULT CHARSET=latin1
Edit#2 @Dtestのチャームリードのように機能しました
DELETE FROM emailTable WHERE NOT EXISTS (
SELECT * FROM (
SELECT MIN(id) minID FROM emailTable
GROUP BY email HAVING COUNT(*) > 0
) AS q
WHERE minID=id
)
これを試して:
DELETE FROM emailTable WHERE NOT EXISTS (
SELECT * FROM (
SELECT MIN(id) minID FROM emailTable
GROUP BY email HAVING COUNT(*) > 0
) AS q
WHERE minID=id
)
上記は、50通のメールのテスト(5通の異なるメールが10回複製された)で機能しました。
'email'列にインデックスを追加する必要があるかもしれません:
ALTER TABLE emailTable ADD INDEX ind_email (email);
250,000行から少し遅いかもしれません。 150万行(適切にインデックスが付けられている)を持つテーブルでは、速度が遅くなりました。そのため、この戦略を思い付きました。
/* CREATE MEMORY TABLE TO HOUSE IDs of the MIN */
CREATE TABLE email_min (minID INT, PRIMARY KEY(minID)) ENGINE=Memory;
/* INSERT THE MINIMUM IDs */
INSERT INTO email_min SELECT id FROM email
GROUP BY email HAVING MIN(id);
/* MAKE SURE YOU HAVE RIGHT INFO */
SELECT * FROM email
WHERE NOT EXISTS (SELECT * FROM email_min WHERE minID=id)
/* DELETE FROM EMAIL */
DELETE FROM email
WHERE NOT EXISTS (SELECT * FROM email_min WHERE minID=id)
/* IF ALL IS WELL, DROP MEMORY TABLE */
DROP TABLE email_min;
メモリテーブルの利点は、通常の一時テーブルよりも処理を高速化するために使用されるインデックス(minIDの主キー)があることです。
以下は、より合理化された削除プロセスです。
CREATE TABLE emailUnique LIKE emailTable;
ALTER TABLE emailUnique ADD UNIQUE INDEX (email);
INSERT IGNORE INTO emailUnique SELECT * FROM emailTable;
SELECT * FROM emailUnique;
ALTER TABLE emailTable RENAME emailTable_old;
ALTER TABLE emailUnique RENAME emailTable;
DROP TABLE emailTable_old;
ここにいくつかのサンプルデータがあります:
use test
DROP TABLE IF EXISTS emailTable;
CREATE TABLE `emailTable` (
`id` mediumint(9) NOT NULL auto_increment,
`email` varchar(200) NOT NULL default '',
PRIMARY KEY (`id`)
) ENGINE=MyISAM;
INSERT INTO emailTable (email) VALUES
('[email protected]'),
('[email protected]'),
('[email protected]'),
('[email protected]'),
('[email protected]'),
('[email protected]'),
('[email protected]'),
('[email protected]'),
('[email protected]'),
('[email protected]'),
('[email protected]'),
('[email protected]'),
('[email protected]'),
('[email protected]'),
('[email protected]');
SELECT * FROM emailTable;
私はそれらを実行しました。結果は次のとおりです。
mysql> use test
Database changed
mysql> DROP TABLE IF EXISTS emailTable;
Query OK, 0 rows affected (0.01 sec)
mysql> CREATE TABLE `emailTable` (
-> `id` mediumint(9) NOT NULL auto_increment,
-> `email` varchar(200) NOT NULL default '',
-> PRIMARY KEY (`id`)
-> ) ENGINE=MyISAM;
Query OK, 0 rows affected (0.05 sec)
mysql> INSERT INTO emailTable (email) VALUES
-> ('[email protected]'),
-> ('[email protected]'),
-> ('[email protected]'),
-> ('[email protected]'),
-> ('[email protected]'),
('[email protected]');
SELECT * FROM emailTable;
-> ('[email protected]'),
-> ('[email protected]'),
-> ('[email protected]'),
-> ('[email protected]'),
-> ('[email protected]'),
-> ('[email protected]'),
-> ('[email protected]'),
-> ('[email protected]'),
-> ('[email protected]'),
-> ('[email protected]');
Query OK, 15 rows affected (0.00 sec)
Records: 15 Duplicates: 0 Warnings: 0
mysql> SELECT * FROM emailTable;
+----+----------------------------+
| id | email |
+----+----------------------------+
| 1 | [email protected] |
| 2 | [email protected] |
| 3 | [email protected] |
| 4 | [email protected] |
| 5 | [email protected] |
| 6 | [email protected] |
| 7 | [email protected] |
| 8 | [email protected] |
| 9 | [email protected] |
| 10 | [email protected] |
| 11 | [email protected] |
| 12 | [email protected] |
| 13 | [email protected] |
| 14 | [email protected] |
| 15 | [email protected] |
+----+----------------------------+
15 rows in set (0.00 sec)
mysql> CREATE TABLE emailUnique LIKE emailTable;
Query OK, 0 rows affected (0.04 sec)
mysql> ALTER TABLE emailUnique ADD UNIQUE INDEX (email);
Query OK, 0 rows affected (0.06 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> INSERT IGNORE INTO emailUnique SELECT * FROM emailTable;
Query OK, 4 rows affected (0.01 sec)
Records: 15 Duplicates: 11 Warnings: 0
mysql> SELECT * FROM emailUnique;
+----+----------------------------+
| id | email |
+----+----------------------------+
| 1 | [email protected] |
| 5 | [email protected] |
| 8 | [email protected] |
| 13 | [email protected] |
+----+----------------------------+
4 rows in set (0.00 sec)
mysql> ALTER TABLE emailTable RENAME emailTable_old;
Query OK, 0 rows affected (0.03 sec)
mysql> ALTER TABLE emailUnique RENAME emailTable;
Query OK, 0 rows affected (0.00 sec)
mysql> DROP TABLE emailTable_old;
Query OK, 0 rows affected (0.00 sec)
mysql>
示されているように、emailTableには各電子メールアドレスの最初の出現と対応する元のIDが含まれます。この例では:
警告: 一時テーブルアプローチによるテーブルの削除に関するこれと同様の質問に答えました 。
試してみる !!!
これが実際の簡単なItzikソリューションです。これはSQL 2005以降で機能します。
WITH Dups AS
(
SELECT *,
ROW_NUMBER()
OVER(PARTITION BY email ORDER BY id) AS rn
FROM dbo.emailTable
)
DELETE FROM Dups
WHERE rn > 1;