Xóa tất cả các bản sao


8

Tôi đang cố gắng xóa tất cả các bản sao nhưng chỉ giữ một bản ghi (id ngắn hơn). Theo truy vấn sẽ xóa các bản sao nhưng mất nhiều lần lặp để xóa tất cả các bản sao và giữ bản gốc.

DELETE FROM emailTable WHERE id IN (
 SELECT * FROM (
    SELECT id FROM emailTable GROUP BY email HAVING ( COUNT(email) > 1 )
 ) AS q
)

MySQL của nó.

Chỉnh sửa # 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

Chỉnh sửa # 2 Nó hoạt động như một nhân vật quyến rũ của @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
)

Câu trả lời:


8

Thử cái này:

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
)

Ở trên đã làm việc cho thử nghiệm của tôi 50 email (5 email khác nhau được nhân đôi 10 lần).

Bạn có thể cần thêm một chỉ mục trên cột 'email':

ALTER TABLE emailTable ADD INDEX ind_email (email);

Nó có thể chậm một chút 250.000 hàng. Nó rất chậm đối với tôi trên một bảng có 1,5 triệu hàng (được lập chỉ mục chính xác), đó là cách tôi đưa ra chiến lược này:

/* 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;

Lợi ích của bảng bộ nhớ là có một chỉ mục được sử dụng (khóa chính trên minID) giúp tăng tốc quá trình trên một bảng tạm thời bình thường.


4

Đây là một quá trình xóa hợp lý hơn:

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;

Đây là một số dữ liệu mẫu:

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
('redwards@gmail.com'),
('redwards@gmail.com'),
('redwards@gmail.com'),
('redwards@gmail.com'),
('rolandoedwards@gmail.com'),
('rolandoedwards@gmail.com'),
('rolandoedwards@gmail.com'),
('red@gmail.com'),
('red@gmail.com'),
('red@gmail.com'),
('rolandoedwards@gmail.com'),
('rolandoedwards@gmail.com'),
('rolandoedwards@comcast.net'),
('rolandoedwards@comcast.net'),
('rolandoedwards@comcast.net');
SELECT * FROM emailTable;

Tôi đã chạy chúng. Đây là kết quả:

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
    -> ('redwards@gmail.com'),
    -> ('redwards@gmail.com'),
    -> ('redwards@gmail.com'),
    -> ('redwards@gmail.com'),
    -> ('rolandoedwards@gmail.com'),
('rolandoedwards@comcast.net');
SELECT * FROM emailTable;
    -> ('rolandoedwards@gmail.com'),
    -> ('rolandoedwards@gmail.com'),
    -> ('red@gmail.com'),
    -> ('red@gmail.com'),
    -> ('red@gmail.com'),
    -> ('rolandoedwards@gmail.com'),
    -> ('rolandoedwards@gmail.com'),
    -> ('rolandoedwards@comcast.net'),
    -> ('rolandoedwards@comcast.net'),
    -> ('rolandoedwards@comcast.net');
Query OK, 15 rows affected (0.00 sec)
Records: 15  Duplicates: 0  Warnings: 0

mysql> SELECT * FROM emailTable;
+----+----------------------------+
| id | email                      |
+----+----------------------------+
|  1 | redwards@gmail.com         |
|  2 | redwards@gmail.com         |
|  3 | redwards@gmail.com         |
|  4 | redwards@gmail.com         |
|  5 | rolandoedwards@gmail.com   |
|  6 | rolandoedwards@gmail.com   |
|  7 | rolandoedwards@gmail.com   |
|  8 | red@gmail.com              |
|  9 | red@gmail.com              |
| 10 | red@gmail.com              |
| 11 | rolandoedwards@gmail.com   |
| 12 | rolandoedwards@gmail.com   |
| 13 | rolandoedwards@comcast.net |
| 14 | rolandoedwards@comcast.net |
| 15 | rolandoedwards@comcast.net |
+----+----------------------------+
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 | redwards@gmail.com         |
|  5 | rolandoedwards@gmail.com   |
|  8 | red@gmail.com              |
| 13 | rolandoedwards@comcast.net |
+----+----------------------------+
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>

Như được hiển thị, emailTable sẽ chứa lần xuất hiện đầu tiên của mỗi địa chỉ email và id gốc tương ứng. Ví dụ này:

  • ID 1-4 có redwards @ gmail, nhưng chỉ có 1 được bảo tồn.
  • ID 5-7,11,12 có rolandoedwards @ gmail, nhưng chỉ có 5 được bảo tồn.
  • ID 8-10 có red @ gmail, nhưng chỉ có 8 được bảo tồn.
  • ID 13-15 có rolandoedwards@comcast.net, nhưng chỉ có 13 được bảo tồn.

CAVEAT: Tôi đã trả lời một câu hỏi tương tự như điều này liên quan đến việc xóa bảng bằng phương pháp tiếp cận bảng tạm thời .

Hãy thử một lần !!!


Tôi chỉnh sửa câu hỏi của tôi về truy vấn tôi thấy làm việc. Mặc dù truy vấn đó là đơn giản. Nhưng tôi nghĩ về mặt kỹ thuật giải pháp của bạn sẽ tốt hơn nếu nó được thực hiện trên bàn lớn?
Gary Lindahl

2
Câu trả lời từ @DTest là tương tự (sử dụng bảng bên ngoài) nhưng sử dụng bảng tạm thời MEMOR, có các khóa được lưu trữ trong chỉ mục HASH thay vì BTREE. Nó có thể sẽ làm việc nhanh hơn. Về kích thước của dữ liệu, miễn là có đủ RAM để chứa các phím, đó là một giải pháp tốt. Đẹp một, DTest.
RolandoMySQLDBA

2

Đây là một giải pháp Itzik thực sự nhanh chóng. Điều này sẽ hoạt động trong SQL 2005 và lớn hơn.

WITH Dups AS
(
  SELECT *,
    ROW_NUMBER()
      OVER(PARTITION BY email ORDER BY id) AS rn
  FROM dbo.emailTable
)
DELETE FROM Dups
WHERE rn > 1;

OP đang yêu cầu MySQL
Derek Downey

2
Vâng, chỉ cần nhận ra rằng; doh! Chà, đó là một giải pháp tuyệt vời cho MS SQL :)
Delux

Không tệ khi biết về MS SQL: p nhưng hiện tại đang tìm kiếm giải pháp MySQL.
Gary Lindahl
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.