Xóa các hàng trùng lặp trong MySQL


375

Tôi có một bảng với các trường sau:

id (Unique)
url (Unique)
title
company
site_id

Bây giờ, tôi cần phải loại bỏ các hàng có cùng title, company and site_id. Một cách để làm điều đó sẽ là sử dụng SQL sau cùng với tập lệnh ( PHP):

SELECT title, site_id, location, id, count( * ) 
FROM jobs
GROUP BY site_id, company, title, location
HAVING count( * ) >1

Sau khi chạy truy vấn này, tôi có thể loại bỏ các bản sao bằng cách sử dụng tập lệnh phía máy chủ.

Nhưng, tôi muốn biết nếu điều này có thể được thực hiện chỉ bằng cách sử dụng truy vấn SQL.


1
Câu hỏi nhanh: không phải lúc nào cũng muốn trùng lặp (tiêu đề, công ty, site_id)? Nếu vậy, tôi đã thiết lập một ràng buộc trong cơ sở dữ liệu để thực thi tiêu đề, công ty và site_id là duy nhất. Điều đó có nghĩa là bạn sẽ không cần một quá trình dọn dẹp. Và nó chỉ mất một dòng SQL.
J. Polfer

1
Vui lòng tham khảo liên kết này của stackoverflow . Nó hoạt động đối với tôi như một cơ duyên.

Tôi có thể đề xuất giải pháp này (được đăng trong một chủ đề khác): stackoverflow.com/a/4685232/195835
Simon East

Bạn cũng có thể kiểm tra câu trả lời này
Jose Rui Santos

Câu trả lời:


607

Một cách thực sự dễ dàng để làm điều này là thêm một UNIQUEchỉ mục trên 3 cột. Khi bạn viết ALTERtuyên bố, bao gồm IGNOREtừ khóa. Thích như vậy:

ALTER IGNORE TABLE jobs
ADD UNIQUE INDEX idx_name (site_id, title, company);

Điều này sẽ thả tất cả các hàng trùng lặp. Là một lợi ích bổ sung, tương lai INSERTslà các bản sao sẽ bị lỗi. Như mọi khi, bạn có thể muốn sao lưu trước khi chạy một cái gì đó như thế này ...


8
Thật thú vị , nhưng các giả định mà mệnh đề IGNORE đưa ra để loại bỏ các bản sao đó là mối quan tâm có thể không phù hợp với nhu cầu. Giá trị không chính xác bị cắt cụt để phù hợp nhất có thể chấp nhận âm thanh tốt với bạn?
Ngựa Non OMG

75
Chỉ dành cho bản ghi nếu bạn sử dụng InnoDB thì bạn có thể gặp sự cố với nó, có một lỗi đã biết về việc sử dụng ALTER IGNORE TABLE với cơ sở dữ liệu InnoDB.
DarkMantis

27
Lỗi nói trên @DarkMantis đã đề cập và đó là giải pháp .
Jordan Arseno

42
Đối với các bảng InnoDB, trước tiên hãy thực hiện truy vấn sau:set session old_alter_table=1;
shock_one

51
Điều này không còn hỗ trợ trong 5.7.4, dev.mysql.com/doc/refman/5.7/en/alter-table.html
Ray Baxter

180

Nếu bạn không muốn thay đổi các thuộc tính cột, thì bạn có thể sử dụng truy vấn bên dưới.

Vì bạn có một cột có ID duy nhất (ví dụ: auto_incrementcác cột), bạn có thể sử dụng nó để loại bỏ các bản sao:

DELETE `a`
FROM
    `jobs` AS `a`,
    `jobs` AS `b`
WHERE
    -- IMPORTANT: Ensures one version remains
    -- Change "ID" to your unique column's name
    `a`.`ID` < `b`.`ID`

    -- Any duplicates you want to check for
    AND (`a`.`title` = `b`.`title` OR `a`.`title` IS NULL AND `b`.`title` IS NULL)
    AND (`a`.`company` = `b`.`company` OR `a`.`company` IS NULL AND `b`.`company` IS NULL)
    AND (`a`.`site_id` = `b`.`site_id` OR `a`.`site_id` IS NULL AND `b`.`site_id` IS NULL);

Trong MySQL, bạn có thể đơn giản hóa nó nhiều hơn nữa với toán tử bằng NULL-safe (hay còn gọi là "toán tử tàu vũ trụ" ):

DELETE `a`
FROM
    `jobs` AS `a`,
    `jobs` AS `b`
WHERE
    -- IMPORTANT: Ensures one version remains
    -- Change "ID" to your unique column's name
    `a`.`ID` < `b`.`ID`

    -- Any duplicates you want to check for
    AND `a`.`title` <=> `b`.`title`
    AND `a`.`company` <=> `b`.`company`
    AND `a`.`site_id` <=> `b`.`site_id`;

3
Giải pháp này không hoạt động đúng, tôi đã thử tạo một số bản ghi trùng lặp và nó thực hiện một số thứ như (20 hàng bị ảnh hưởng) nhưng nếu bạn chạy lại, nó sẽ hiển thị cho bạn (4 hàng bị ảnh hưởng) và cứ thế cho đến khi bạn đạt (0 hàng bị ảnh hưởng) Điều này thật đáng ngờ và đây là điều tốt nhất đối với tôi, nó gần như giống nhau nhưng nó hoạt động trong một lần chạy, tôi đã chỉnh sửa giải pháp
Nassim

1
@Nassim: Bạn phải làm điều gì đó khác với câu trả lời này vì nó hoạt động hoàn hảo với tôi (trong MySQL).
Lawrence Dol

3
Đối với bất kỳ ai bị nhầm lẫn như tôi, các thuật ngữ so sánh NULL là cần thiết vì NULL không bằng NULL trong MySQL. Nếu các cột có liên quan được đảm bảo không phải là NULL, bạn có thể loại bỏ các điều khoản này.
Ian

3
Có, câu trả lời được chấp nhận không còn hiệu lực, vì MYSQL 5.7 vì vậy đây thực sự phải là câu trả lời được chấp nhận vì nó phổ biến và cũng không yêu cầu tạo bảng tạm thời.
đó là

1
RẤT SLOW nếu có NHIỀU bản sao của một bản ghi đã cho (ví dụ: giảm 100 xuống còn 1) và nhiều bản ghi với điều kiện đó. Đề nghị stackoverflow.com/a/4685232/199364 thay thế. IMHO, LUÔN LUÔN sử dụng phương pháp liên kết; đó là một kỹ thuật vốn đã nhanh hơn.
ToolmakerSteve

78

MySQL có các hạn chế về việc tham khảo bảng bạn đang xóa. Bạn có thể làm việc xung quanh đó với một bảng tạm thời, như:

create temporary table tmpTable (id int);

insert  into tmpTable
        (id)
select  id
from    YourTable yt
where   exists
        (
        select  *
        from    YourTabe yt2
        where   yt2.title = yt.title
                and yt2.company = yt.company
                and yt2.site_id = yt.site_id
                and yt2.id > yt.id
        );

delete  
from    YourTable
where   ID in (select id from tmpTable);

Từ đề xuất của Kostanos trong các bình luận:
Truy vấn chậm duy nhất ở trên là XÓA, đối với trường hợp bạn có cơ sở dữ liệu rất lớn. Truy vấn này có thể nhanh hơn:

DELETE FROM YourTable USING YourTable, tmpTable WHERE YourTable.id=tmpTable.id

3
@andomar, điều này hoạt động tốt trừ khi một trong các trường trong mệnh đề where chứa null. Ví dụ: sqlfiddle.com/#!2/983f3/1
một lập trình viên

1
Là SQL chèn là một đắt tiền? Tôi đang tự hỏi bởi vì nó hết thời gian trong cơ sở dữ liệu MySQL của tôi.
Cassio

4
Truy vấn chậm duy nhất ở đây là truy vấn XÓA, trong trường hợp khi bạn có cơ sở dữ liệu lớn. Truy vấn này có thể nhanh hơn:DELETE FROM YourTable USING YourTable, tmpTable WHERE YourTable.id=tmpTable.id
Kostanos

@Kostanos Không chỉ DELETE, mà còn INSERTđến bàn tạm thời, tôi phải mất một thời gian dài. Vì vậy, một chỉ mục cho bảng tmp có thể giúp ích rất nhiều, create index tmpTable_id_index on tmpTable (id)ít nhất là cho tôi.
Jiezhi.G

1
Nếu các bảng của bạn lớn, đáng để thêm một chỉ mục với: -create temporary table tmpTable (id int, PRIMARY KEY (id));
Dallas Clarke

44

Nếu IGNOREcâu lệnh không hoạt động như trong trường hợp của tôi, bạn có thể sử dụng câu lệnh dưới đây:

CREATE TABLE your_table_deduped LIKE your_table;


INSERT your_table_deduped
SELECT *
FROM your_table
GROUP BY index1_id,
         index2_id;

RENAME TABLE your_table TO your_table_with_dupes;

RENAME TABLE your_table_deduped TO your_table;

#OPTIONAL
ALTER TABLE `your_table` ADD UNIQUE `unique_index` (`index1_id`, `index2_id`);

#OPTIONAL
DROP TABLE your_table_with_dupes;

1
hoạt động tuyệt vời nếu bạn có cài đặt innoDB với ràng buộc khóa ngoài.
magdmartin

@magdmartin, nhưng sẽ không hạn chế nước ngoài ngăn chặn xóa bảng?
Basilevs

1
Tuyên bố của IGNORE đã không làm việc cho tôi và điều này đã làm việc rất tốt khi trích 5 triệu hồ sơ. Chúc mừng.
Mauvis Ledford

32

Xóa các bản sao trên các bảng MySQL là một vấn đề phổ biến, đó thực sự là kết quả của một ràng buộc bị thiếu để tránh các bản sao đó trước khi xử lý. Nhưng vấn đề phổ biến này thường đi kèm với các nhu cầu cụ thể ... đòi hỏi phải có cách tiếp cận cụ thể. Cách tiếp cận nên khác nhau tùy thuộc vào, ví dụ, kích thước của dữ liệu, mục nhập trùng lặp nên được giữ (nói chung là đầu tiên hoặc cuối cùng), liệu có các chỉ mục được giữ hay không, hoặc chúng tôi muốn thực hiện bất kỳ bổ sung nào hành động trên dữ liệu trùng lặp.

Ngoài ra còn có một số đặc điểm cụ thể trên MySQL, chẳng hạn như không thể tham chiếu cùng một bảng với nguyên nhân TỪ khi thực hiện bảng CẬP NHẬT (nó sẽ gây ra lỗi MySQL # 1093). Hạn chế này có thể được khắc phục bằng cách sử dụng truy vấn bên trong với bảng tạm thời (như được đề xuất trên một số phương pháp ở trên). Nhưng truy vấn bên trong này sẽ không thực hiện đặc biệt tốt khi xử lý các nguồn dữ liệu lớn.

Tuy nhiên, một cách tiếp cận tốt hơn tồn tại để loại bỏ các bản sao, điều đó vừa hiệu quả vừa đáng tin cậy và có thể dễ dàng thích nghi với các nhu cầu khác nhau.

Ý tưởng chung là tạo một bảng tạm thời mới, thường thêm một ràng buộc duy nhất để tránh trùng lặp thêm và để XÁC NHẬN dữ liệu từ bảng cũ của bạn sang bảng mới, trong khi chăm sóc các bản sao. Cách tiếp cận này dựa trên các truy vấn MySQL INSERT đơn giản, tạo ra một ràng buộc mới để tránh trùng lặp thêm và bỏ qua nhu cầu sử dụng truy vấn bên trong để tìm kiếm các bản sao và bảng tạm thời nên được giữ trong bộ nhớ (do đó cũng phù hợp với các nguồn dữ liệu lớn).

Đây là cách nó có thể đạt được. Cho rằng chúng tôi có một nhân viên bảng , với các cột sau:

employee (id, first_name, last_name, start_date, ssn)

Để xóa các hàng có cột ssn trùng lặp và chỉ giữ lại mục nhập đầu tiên được tìm thấy, có thể thực hiện quy trình sau:

-- create a new tmp_eployee table
CREATE TABLE tmp_employee LIKE employee;

-- add a unique constraint
ALTER TABLE tmp_employee ADD UNIQUE(ssn);

-- scan over the employee table to insert employee entries
INSERT IGNORE INTO tmp_employee SELECT * FROM employee ORDER BY id;

-- rename tables
RENAME TABLE employee TO backup_employee, tmp_employee TO employee;

Giải thích kỹ thuật

  • Dòng # 1 tạo bảng tmp_eployee mới với cấu trúc chính xác giống như bảng nhân viên
  • Dòng # 2 thêm một ràng buộc ĐỘC ĐÁO vào bảng tmp_eployee mới để tránh bất kỳ sự trùng lặp nào nữa
  • Dòng số 3 quét qua bảng nhân viên ban đầu theo id, chèn các mục nhập nhân viên mới vào bảng tmp_eployee mới , trong khi bỏ qua các mục trùng lặp
  • Dòng số 4 đổi tên các bảng, để bảng nhân viên mới giữ tất cả các mục nhập mà không trùng lặp và một bản sao lưu dữ liệu cũ được giữ trên bảng backup_employee

Sử dụng phương pháp này, 1,6 triệu đăng ký được chuyển đổi thành 6k trong vòng chưa đầy 200s.

Chetan , theo quy trình này, bạn có thể nhanh chóng và dễ dàng loại bỏ tất cả các bản sao của mình và tạo ra một ràng buộc ĐỘC ĐÁO bằng cách chạy:

CREATE TABLE tmp_jobs LIKE jobs;

ALTER TABLE tmp_jobs ADD UNIQUE(site_id, title, company);

INSERT IGNORE INTO tmp_jobs SELECT * FROM jobs ORDER BY id;

RENAME TABLE jobs TO backup_jobs, tmp_jobs TO jobs;

Tất nhiên, quá trình này có thể được sửa đổi thêm để điều chỉnh nó cho các nhu cầu khác nhau khi xóa các bản sao. Một số ví dụ sau đây.

✔ Biến thể để giữ mục cuối cùng thay vì mục đầu tiên

Đôi khi chúng ta cần giữ mục nhập trùng lặp cuối cùng thay vì mục đầu tiên.

CREATE TABLE tmp_employee LIKE employee;

ALTER TABLE tmp_employee ADD UNIQUE(ssn);

INSERT IGNORE INTO tmp_employee SELECT * FROM employee ORDER BY id DESC;

RENAME TABLE employee TO backup_employee, tmp_employee TO employee;
  • Trên dòng số 3, mệnh đề ORDER BY id DESC làm cho ID cuối cùng được ưu tiên hơn phần còn lại

✔ Biến thể để thực hiện một số tác vụ trên các bản sao, ví dụ: giữ số lượng trên các bản sao được tìm thấy

Đôi khi chúng ta cần thực hiện một số xử lý tiếp theo đối với các mục trùng lặp được tìm thấy (chẳng hạn như giữ một số lượng trùng lặp).

CREATE TABLE tmp_employee LIKE employee;

ALTER TABLE tmp_employee ADD UNIQUE(ssn);

ALTER TABLE tmp_employee ADD COLUMN n_duplicates INT DEFAULT 0;

INSERT INTO tmp_employee SELECT * FROM employee ORDER BY id ON DUPLICATE KEY UPDATE n_duplicates=n_duplicates+1;

RENAME TABLE employee TO backup_employee, tmp_employee TO employee;
  • Trên dòng số 3, một cột mới n_d repeatates được tạo
  • Trên dòng số 4, truy vấn INSERT INTO ... ON DUPLICATE KEY UPDATE được sử dụng để thực hiện cập nhật bổ sung khi tìm thấy bản sao (trong trường hợp này, tăng bộ đếm) Có thể truy vấn INSERT INTO ... ON DUPLICATE KEY UPDATE được sử dụng để thực hiện các loại cập nhật khác nhau cho các bản sao được tìm thấy.

✔ Biến thể để tạo lại id trường tăng tự động

Đôi khi chúng tôi sử dụng trường tăng tự động và để giữ cho chỉ số càng nhỏ gọn càng tốt, chúng tôi có thể tận dụng việc xóa các bản sao để tạo lại trường tăng tự động trong bảng tạm thời mới.

CREATE TABLE tmp_employee LIKE employee;

ALTER TABLE tmp_employee ADD UNIQUE(ssn);

INSERT IGNORE INTO tmp_employee SELECT (first_name, last_name, start_date, ssn) FROM employee ORDER BY id;

RENAME TABLE employee TO backup_employee, tmp_employee TO employee;
  • Trên dòng số 3, thay vì chọn tất cả các trường trên bảng, trường id được bỏ qua để công cụ DB tự động tạo một trường mới

✔ Các biến thể khác

Nhiều sửa đổi thêm cũng có thể thực hiện được tùy thuộc vào hành vi mong muốn. Ví dụ: các truy vấn sau sẽ sử dụng bảng tạm thời thứ hai để, ngoài 1) giữ mục nhập cuối cùng thay vì mục đầu tiên; và 2) tăng bộ đếm trên các bản sao được tìm thấy; cũng 3) tạo lại id trường tăng tự động trong khi vẫn giữ thứ tự nhập như trên dữ liệu cũ.

CREATE TABLE tmp_employee LIKE employee;

ALTER TABLE tmp_employee ADD UNIQUE(ssn);

ALTER TABLE tmp_employee ADD COLUMN n_duplicates INT DEFAULT 0;

INSERT INTO tmp_employee SELECT * FROM employee ORDER BY id DESC ON DUPLICATE KEY UPDATE n_duplicates=n_duplicates+1;

CREATE TABLE tmp_employee2 LIKE tmp_employee;

INSERT INTO tmp_employee2 SELECT (first_name, last_name, start_date, ssn) FROM tmp_employee ORDER BY id;

DROP TABLE tmp_employee;

RENAME TABLE employee TO backup_employee, tmp_employee2 TO employee;

27

Có một giải pháp khác:

DELETE t1 FROM my_table t1, my_table t2 WHERE t1.id < t2.id AND t1.my_field = t2.my_field AND t1.my_field_2 = t2.my_field_2 AND ...

4
Điều này khác với câu trả lời của @ Rehriff, mà anh ấy đã gửi 6 tháng trước đó?
Lawrence Dol

@LawrenceDol Tôi đoán nó dễ đọc hơn một chút và tôi cũng nghĩ câu trả lời của anh ấy không giống lúc tôi trả lời và tôi nghĩ câu trả lời của anh ấy đã được chỉnh sửa.
Mostafa -T

1
hmm Nó mất quá nhiều thời gian cho tôi trong khi số lượng hồ sơ không lớn!
SuB

8

nếu bạn có một bảng lớn với số lượng hồ sơ khổng lồ thì các giải pháp trên sẽ không hoạt động hoặc mất quá nhiều thời gian. Sau đó, chúng tôi có một giải pháp khác nhau

-- Create temporary table

CREATE TABLE temp_table LIKE table1;

-- Add constraint
ALTER TABLE temp_table ADD UNIQUE(title, company,site_id);

-- Copy data
INSERT IGNORE INTO temp_table SELECT * FROM table1;

-- Rename and drop
RENAME TABLE table1 TO old_table1, temp_table TO table1;
DROP TABLE old_table1;

6

Tôi có đoạn mã truy vấn này cho SQLServer nhưng tôi nghĩ nó có thể được sử dụng trong các DBMS khác với ít thay đổi:

DELETE
FROM Table
WHERE Table.idTable IN  (  
    SELECT MAX(idTable)
    FROM idTable
    GROUP BY field1, field2, field3
    HAVING COUNT(*) > 1)

Tôi quên nói với bạn rằng truy vấn này không xóa hàng có id thấp nhất trong các hàng trùng lặp. Nếu điều này làm việc cho bạn hãy thử truy vấn này:

DELETE
FROM jobs
WHERE jobs.id IN  (  
    SELECT MAX(id)
    FROM jobs
    GROUP BY site_id, company, title, location
    HAVING COUNT(*) > 1)

Điều đó sẽ không hiệu quả nếu có nhiều hơn hai bản sao của một nhóm.
Ngựa Non OMG

11
Thật không may, MySQL không cho phép bạn chọn từ bảng bạn đang xóa từERROR 1093: You can't specify target table 'Table' for update in FROM clause
Andomar

1
Để giải quyết "You can't specify target table 'Table' for update in FROM..."lỗi, sử dụng: DELETE FROM Table WHERE Table.idTable IN ( SELECT MAX(idTable) FROM (SELECT * FROM idTable) AS tmp GROUP BY field1, field2, field3 HAVING COUNT(*) > 1)buộc MySQL phải tạo bảng tạm thời. Tuy nhiên, rất chậm trong các bộ dữ liệu lớn ... trong những trường hợp như vậy, tôi sẽ đề xuất mã của Andomar, nhanh hơn nhiều.
lepe

6

Cách nhanh hơn là chèn các hàng riêng biệt vào một bảng tạm thời. Sử dụng xóa, tôi mất vài giờ để xóa các bản sao khỏi bảng 8 triệu hàng. Sử dụng chèn và khác biệt, chỉ mất 13 phút.

CREATE TABLE tempTableName LIKE tableName;  
CREATE INDEX ix_all_id ON tableName(cellId,attributeId,entityRowId,value);  
INSERT INTO tempTableName(cellId,attributeId,entityRowId,value) SELECT DISTINCT cellId,attributeId,entityRowId,value FROM tableName;  
TRUNCATE TABLE tableName;
INSERT INTO tableName SELECT * FROM tempTableName; 
DROP TABLE tempTableName;  

1
Dòng thứ 4 của bạn nên nói TRUNCATE TABLE tableNamevà dòng thứ 5 nên nóiINSERT INTO tableName SELECT * FROM tempTableName;
Sana

5

Một giải pháp đơn giản để hiểu và hoạt động không có khóa chính:

1) thêm một cột boolean mới

alter table mytable add tokeep boolean;

2) thêm một ràng buộc trên các cột trùng lặp VÀ cột mới

alter table mytable add constraint preventdupe unique (mycol1, mycol2, tokeep);

3) đặt cột boolean thành true. Điều này sẽ chỉ thành công trên một trong các hàng trùng lặp vì ràng buộc mới

update ignore mytable set tokeep = true;

4) xóa các hàng chưa được đánh dấu là tokeep

delete from mytable where tokeep is null;

5) thả cột đã thêm

alter table mytable drop tokeep;

Tôi đề nghị bạn giữ các ràng buộc bạn đã thêm, để ngăn chặn các bản sao mới trong tương lai.


1
Điều này hoạt động rất tốt trong mysql 5.7 nơi giải pháp được chấp nhận không hoạt động nữa
Robin31

5

Xóa các hàng trùng lặp bằng cách sử dụng câu lệnh DELETE THAM GIA MySQL cung cấp cho bạn câu lệnh DELETE THAM GIA mà bạn có thể sử dụng để xóa các hàng trùng lặp một cách nhanh chóng.

Câu lệnh sau xóa các hàng trùng lặp và giữ id cao nhất:

DELETE t1 FROM contacts t1
    INNER JOIN
contacts t2 WHERE
t1.id < t2.id AND t1.email = t2.email;

5

Tôi tìm thấy một cách đơn giản. (giữ mới nhất)

DELETE t1 FROM tablename t1 INNER JOIN tablename t2 
WHERE t1.id < t2.id AND t1.column1 = t2.column1 AND t1.column2 = t2.column2;

4

Đơn giản và nhanh chóng cho mọi trường hợp:

CREATE TEMPORARY TABLE IF NOT EXISTS _temp_duplicates AS (SELECT dub.id FROM table_with_duplications dub GROUP BY dub.field_must_be_uniq_1, dub.field_must_be_uniq_2 HAVING COUNT(*)  > 1);

DELETE FROM table_with_duplications WHERE id IN (SELECT id FROM _temp_duplicates);

Mã lỗi: 1055. Biểu thức # 2 của danh sách CHỌN không nằm trong mệnh đề GROUP BY và chứa cột không được phân chia 'dub.id' không phụ thuộc chức năng vào các cột trong mệnh đề GROUP BY; cái này không tương thích với sql_mode = only_full_group_by
Swoogan

bạn có thể vô hiệu hóa "điều khiển cứng" với sql_mode, xem stackoverflow.com/questions/23921117/disable-only-full-group-by
artemiuz

4

Điều này sẽ xóa các hàng trùng lặp với cùng giá trị cho tiêu đề, công ty và trang web. Sự xuất hiện đầu tiên sẽ được giữ và phần còn lại tất cả các bản sao sẽ bị xóa

DELETE t1 FROM tablename t1
INNER JOIN tablename t2 
WHERE 
    t1.id < t2.id AND
    t1.title = t2.title AND
    t1.company=t2.company AND
    t1.site_ID=t2.site_ID;

nó chậm (5w + hàng, thời gian chờ khóa) nhưng đã hoạt động
yurenchen

3

Tôi tiếp tục truy cập trang này bất cứ khi nào tôi google "xóa các bản sao mẫu mysql" nhưng đối với các giải pháp của chúng tôi không hoạt động vì tôi có bảng mysql của InnoDB

mã này hoạt động tốt hơn bất cứ lúc nào

CREATE TABLE tableToclean_temp LIKE tableToclean;
ALTER TABLE tableToclean_temp ADD UNIQUE INDEX (fontsinuse_id);
INSERT IGNORE INTO tableToclean_temp SELECT * FROM tableToclean;
DROP TABLE tableToclean;
RENAME TABLE tableToclean_temp TO tableToclean;

tableToclean = tên của bảng bạn cần xóa

tableToclean_temp = một bảng tạm thời được tạo và xóa


2

Giải pháp này sẽ di chuyển các bản sao vào một bảng và các đơn vị này sang một bảng khác .

-- speed up creating uniques table if dealing with many rows
CREATE INDEX temp_idx ON jobs(site_id, company, title, location);

-- create the table with unique rows
INSERT jobs_uniques SELECT * FROM
    (
    SELECT * 
    FROM jobs
    GROUP BY site_id, company, title, location
    HAVING count(1) > 1
    UNION
    SELECT *
    FROM jobs
    GROUP BY site_id, company, title, location
    HAVING count(1) = 1
) x

-- create the table with duplicate rows
INSERT jobs_dupes 
SELECT * 
FROM jobs
WHERE id NOT IN
(SELECT id FROM jobs_uniques)

-- confirm the difference between uniques and dupes tables
SELECT COUNT(1)
AS jobs, 
(SELECT COUNT(1) FROM jobs_dupes) + (SELECT COUNT(1) FROM jobs_uniques)
AS sum
FROM jobs

Tại sao bạn lấy liên minh và không chỉ SELECT * FROM jobs GROUP BY site_id, company, title, location?
timctran

2

Kể từ phiên bản 8.0 (2018), MySQL cuối cùng cũng hỗ trợ các chức năng của cửa sổ .

Các chức năng của cửa sổ đều tiện dụng và hiệu quả. Dưới đây là một giải pháp cho thấy cách sử dụng chúng để giải quyết nhiệm vụ này.

Trong truy vấn con, chúng ta có thể sử dụng ROW_NUMBER()để gán một vị trí cho mỗi bản ghi trong bảng trong column1/column2các nhóm, được sắp xếp theo id. Nếu không có trùng lặp, bản ghi sẽ nhận được số hàng 1. Nếu trùng lặp tồn tại, chúng sẽ được đánh số bằng cách tăng dần id(bắt đầu từ 1).

Khi các bản ghi được đánh số chính xác trong truy vấn con, truy vấn bên ngoài sẽ xóa tất cả các bản ghi có số hàng không phải là 1.

Truy vấn :

DELETE FROM tablename
WHERE id IN (
    SELECT id
    FROM (
        SELECT 
            id, 
            ROW_NUMBER() OVER(PARTITION BY column1, column2 ORDER BY id) rn
        FROM output
    ) t
    WHERE rn > 1
)

1

Để xóa bản ghi trùng lặp trong một bảng.

delete from job s 
where rowid < any 
(select rowid from job k 
where s.site_id = k.site_id and 
s.title = k.title and 
s.company = k.company);

hoặc là

delete from job s 
where rowid not in 
(select max(rowid) from job k 
where s.site_id = k.site_id and
s.title = k.title and 
s.company = k.company);

1
-- Here is what I used, and it works:
create table temp_table like my_table;
-- t_id is my unique column
insert into temp_table (id) select id from my_table GROUP by t_id;
delete from my_table where id not in (select id from temp_table);
drop table temp_table;

0

Để sao chép các bản ghi với các cột duy nhất, ví dụ: COL1, COL2, COL3 không được sao chép (giả sử chúng tôi đã bỏ lỡ 3 cột duy nhất trong cấu trúc bảng và nhiều mục trùng lặp đã được tạo vào bảng)

DROP TABLE TABLE_NAME_copy;
CREATE TABLE TABLE_NAME_copy LIKE TABLE_NAME;
INSERT INTO TABLE_NAME_copy
SELECT * FROM TABLE_NAME
GROUP BY COLUMN1, COLUMN2, COLUMN3; 
DROP TABLE TABLE_NAME;
ALTER TABLE TABLE_NAME_copy RENAME TO TABLE_NAME;

Hy vọng sẽ giúp dev.


0

TL; TR;

Một hướng dẫn được mô tả rất nhiều để giải quyết vấn đề này có thể được tìm thấy tại trang web mysqltutorial.org :

Cách xóa các hàng trùng lặp trong MySQL

Nó được chỉ ra rất rõ cách xóa các hàng trùng lặp theo ba cách khác nhau :

A) Sử dụng DELETE JOINcâu lệnh

B) Sử dụng bảng trung gian

C) Sử dụng ROW_NUMBER()chức năng

Tôi hy vọng rằng nó sẽ giúp được ai đó.


0

Tôi có một bảng mà quên thêm khóa chính trong hàng id. Mặc dù có auto_increment trên id. Nhưng một ngày nọ, một thứ phát lại nhật ký bin mysql trên cơ sở dữ liệu chèn một số hàng trùng lặp.

Tôi xóa hàng trùng lặp bằng

  1. chọn các hàng trùng lặp duy nhất và xuất chúng

select T1.* from table_name T1 inner join (select count(*) as c,id from table_name group by id) T2 on T1.id = T2.id where T2.c > 1 group by T1.id;

  1. xóa các hàng trùng lặp theo id

  2. chèn hàng từ dữ liệu đã xuất.

  3. Sau đó thêm khóa chính vào id


-2

Tôi muốn cụ thể hơn một chút về những bản ghi tôi xóa vì vậy đây là giải pháp của tôi:

delete
from jobs c1
where not c1.location = 'Paris'
and  c1.site_id > 64218
and exists 
(  
select * from jobs c2 
where c2.site_id = c1.site_id
and   c2.company = c1.company
and   c2.location = c1.location
and   c2.title = c1.title
and   c2.site_id > 63412
and   c2.site_id < 64219
)

-4

Bạn có thể dễ dàng xóa các bản ghi trùng lặp từ mã này ..

$qry = mysql_query("SELECT * from cities");
while($qry_row = mysql_fetch_array($qry))
{
$qry2 = mysql_query("SELECT * from cities2 where city = '".$qry_row['city']."'");

if(mysql_num_rows($qry2) > 1){
    while($row = mysql_fetch_array($qry2)){
        $city_arry[] = $row;

        }

    $total = sizeof($city_arry) - 1;
        for($i=1; $i<=$total; $i++){


            mysql_query( "delete from cities2 where town_id = '".$city_arry[$i][0]."'");

            }
    }
    //exit;
}

3
Đây là nhiệm vụ cơ sở dữ liệu hình thức rất xấu nên được thực hiện trong DB, nơi chúng nhanh hơn nhiều, thay vì gửi dữ liệu liên tục giữa php / mysql vì bạn biết rõ hơn cái kia.
Tối đa

-4

Tôi đã phải làm điều này với các trường văn bản và đã vượt qua giới hạn 100 byte trên chỉ mục.

Tôi đã giải quyết điều này bằng cách thêm một cột, thực hiện băm md5 của các trường và thực hiện thay đổi.

ALTER TABLE table ADD `merged` VARCHAR( 40 ) NOT NULL ;
UPDATE TABLE SET merged` = MD5(CONCAT(`col1`, `col2`, `col3`))
ALTER IGNORE TABLE table ADD UNIQUE INDEX idx_name (`merged`);
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.