Làm thế nào để xóa các bản sao trên bảng MySQL?


158

Tôi cần DELETEsao chép các hàng cho sid được chỉ định trên một MySQLbảng.

Làm thế nào tôi có thể làm điều này với một truy vấn SQL?

DELETE (DUPLICATED TITLES) FROM table WHERE SID = "1"

Một cái gì đó như thế này, nhưng tôi không biết làm thế nào để làm điều đó.


Bạn chỉ cần làm một lần hoặc bạn cần phải làm điều đó mọi lúc?
Billy ONeal

Các bản ghi với các bản ghi trùng lặp có cùng một dữ liệu hoặc các phần còn lại của các trường khác nhau không? Nếu bạn có tùy chọn đầu tiên, bạn chỉ cần xóa tất cả các bản ghi nhưng một, nếu bạn có tùy chọn thứ hai, làm thế nào để bạn xác định bản ghi nào bạn muốn giữ?
rael_kid

@Lex Tùy chọn đầu tiên. @Billy tôi cần làm điều đó mọi lúc.
Ali Demirci


1
Có rất nhiều thứ đã thay đổi ở đây trong các phiên bản khác nhau của MySQL. Kiểm tra phiên bản MySQL của bạn một cách cẩn thận trước khi đi vào con đường của bất kỳ giải pháp nào ở đây.
delatbabel

Câu trả lời:


215

điều này loại bỏ trùng lặp tại chỗ, mà không tạo một bảng mới

ALTER IGNORE TABLE `table_name` ADD UNIQUE (title, SID)

lưu ý: chỉ hoạt động tốt nếu chỉ số phù hợp với bộ nhớ


26
Lưu ý: điều này sẽ giữ bản ghi cũ nhất và sẽ xóa những bản mới hơn. Nếu bạn muốn giữ cái mới nhất, bạn không thể làm điều này với ALTER IGNORE.
Haralan Dobrev

9
Dường như không hoạt động với InnoDB. Tôi chạy ALTER TABLE foo ENGINE MyISAMđến làm việc xung quanh nó, thay đổi động cơ trở lại sau.
Martin

13
điều này có thể thất bại trên MySQL> 5.5, nếu vậy hãy sử dụng "set session old_alter_table = 1;" và "đặt phiên old_alter_table = 0;" trước và sau tuyên bố
chillitom


2
@delatbabel Lý do phản đối nó được đưa ra trong trang bạn liên kết đến.
Barmar

133

Giả sử bạn có một bảng employee, với các cột sau:

employee (first_name, last_name, start_date)

Để xóa các hàng với một first_namecột trùng lặp :

delete
from employee using employee,
    employee e1
where employee.id > e1.id
    and employee.first_name = e1.first_name  

1
Bản ghi còn lại sẽ có id tối đa hoặc tối thiểu trong nhóm sao chép của nó?
Ngọn lửa băng giá

Bản ghi còn lại sẽ có id tối thiểu vì đây là bản duy nhất không đáp ứng điều kiện bị xóa
Pablo Guerrero

1
Có vẻ như tham gia employeevào chính nó cho một trận đấu chỉ mục và một lần >kiểm tra một chỉ mục sẽ chậm đối với các bảng lớn. Nó sẽ không thể tốt hơn để SELECT MAX(ID) FROM t GROUP BY uniquerồi JOINđến một kết hợp chính xác của IDđể MAX(ID)?
ebyrob

1
Câu trả lời chính xác! Tiết kiệm thời gian của tôi!
Nesar

56

Theo dõi loại bỏ trùng lặp cho tất cả SID-s, không chỉ một.

Với bảng tạm thời

CREATE TABLE table_temp AS
SELECT * FROM table GROUP BY title, SID;

DROP TABLE table;
RENAME TABLE table_temp TO table;

Kể từ khi temp_tableđược tạo mới, nó không có chỉ mục. Bạn sẽ cần phải tạo lại chúng sau khi loại bỏ trùng lặp. Bạn có thể kiểm tra những chỉ mục bạn có trong bảng vớiSHOW INDEXES IN table

Không có bảng tạm thời:

DELETE FROM `table` WHERE id IN (
  SELECT all_duplicates.id FROM (
    SELECT id FROM `table` WHERE (`title`, `SID`) IN (
      SELECT `title`, `SID` FROM `table` GROUP BY `title`, `SID` having count(*) > 1
    )
  ) AS all_duplicates 
  LEFT JOIN (
    SELECT id FROM `table` GROUP BY `title`, `SID` having count(*) > 1
  ) AS grouped_duplicates 
  ON all_duplicates.id = grouped_duplicates.id 
  WHERE grouped_duplicates.id IS NULL
)

4
NHÓM-ing chỉ tạo một hàng kết quả cho mỗi kết hợp các giá trị của các trường mà bạn nhóm theo. Vì vậy, các bản sao sẽ được loại bỏ.
Kamil Szot

4
Tôi thích cách đầu tiên, quá nhiều thanh lịch ở đây! : B
AglessEssence

1
@fiacre Bạn có thể tạm thời vô hiệu hóa kiểm tra khóa ngoại: stackoverflow.com/questions/15501673/, Bạn cũng có thể mạo hiểm xóa một số hàng mà các bảng khác tham chiếu, nhưng bạn có thể kiểm soát bản ghi nào được chọn vào bảng khấu trừ bằng cách thay đổi truy vấn SELECT * FROM table GROUP BY title, SID;Tất cả phụ thuộc vào mức độ bạn biết những gì bạn đang làm.
Kamil Szot

1
@ahnbizcad Bạn có thể sử dụng bảng tạm thời nhưng sau đó bạn sẽ phải sao chép dữ liệu từ bảng tạm thời sang bảng thông thường. Nếu bạn sử dụng bảng thực, bạn có thể bỏ bảng cũ với các bản sao và đổi tên bảng mới, không trùng với tên cũ.
Kamil Szot

1
Phương thức "không có bảng tạm thời" là gần nhất với giải pháp tốt nhất, tuy nhiên hãy cẩn thận với cách xử lý CHỈ_ULL_GROUP_BY đã thay đổi trong MySQL 5.7.5: dev.mysql.com/doc/refman/5.7/en/group-by-handling.html Tôi đã nhận được điều này để hoạt động bằng cách thay thế "CHỌN id" bằng "CHỌN ANY_VALUE (id) AS id"
delatbabel

53

Xóa các hàng trùng lặp trong MySQL tại chỗ, (Giả sử bạn có dấu thời gian col để sắp xếp theo) walk walk:

Tạo bảng và chèn một số hàng:

create table penguins(foo int, bar varchar(15), baz datetime);
insert into penguins values(1, 'skipper', now());
insert into penguins values(1, 'skipper', now());
insert into penguins values(3, 'kowalski', now());
insert into penguins values(3, 'kowalski', now());
insert into penguins values(3, 'kowalski', now());
insert into penguins values(4, 'rico', now());
select * from penguins;
    +------+----------+---------------------+
    | foo  | bar      | baz                 |
    +------+----------+---------------------+
    |    1 | skipper  | 2014-08-25 14:21:54 |
    |    1 | skipper  | 2014-08-25 14:21:59 |
    |    3 | kowalski | 2014-08-25 14:22:09 |
    |    3 | kowalski | 2014-08-25 14:22:13 |
    |    3 | kowalski | 2014-08-25 14:22:15 |
    |    4 | rico     | 2014-08-25 14:22:22 |
    +------+----------+---------------------+
6 rows in set (0.00 sec)

Loại bỏ các bản sao tại chỗ:

delete a
    from penguins a
    left join(
    select max(baz) maxtimestamp, foo, bar
    from penguins
    group by foo, bar) b
    on a.baz = maxtimestamp and
    a.foo = b.foo and
    a.bar = b.bar
    where b.maxtimestamp IS NULL;
Query OK, 3 rows affected (0.01 sec)
select * from penguins;
+------+----------+---------------------+
| foo  | bar      | baz                 |
+------+----------+---------------------+
|    1 | skipper  | 2014-08-25 14:21:59 |
|    3 | kowalski | 2014-08-25 14:22:15 |
|    4 | rico     | 2014-08-25 14:22:22 |
+------+----------+---------------------+
3 rows in set (0.00 sec)

Bạn đã hoàn tất, các hàng trùng lặp được xóa, lần cuối cùng bằng dấu thời gian được giữ lại.

Đối với những người không có dấu thời gian hoặc cột duy nhất.

Bạn không có timestamphoặc một cột chỉ mục duy nhất để sắp xếp theo? Bạn đang sống trong tình trạng thoái hóa. Bạn sẽ phải làm các bước bổ sung để xóa các hàng trùng lặp.

tạo bảng chim cánh cụt và thêm một số hàng

create table penguins(foo int, bar varchar(15)); 
insert into penguins values(1, 'skipper'); 
insert into penguins values(1, 'skipper'); 
insert into penguins values(3, 'kowalski'); 
insert into penguins values(3, 'kowalski'); 
insert into penguins values(3, 'kowalski'); 
insert into penguins values(4, 'rico'); 
select * from penguins; 
    # +------+----------+ 
    # | foo  | bar      | 
    # +------+----------+ 
    # |    1 | skipper  | 
    # |    1 | skipper  | 
    # |    3 | kowalski | 
    # |    3 | kowalski | 
    # |    3 | kowalski | 
    # |    4 | rico     | 
    # +------+----------+ 

tạo một bản sao của bảng đầu tiên và sao chép vào nó.

drop table if exists penguins_copy; 
create table penguins_copy as ( SELECT foo, bar FROM penguins );  

#add an autoincrementing primary key: 
ALTER TABLE penguins_copy ADD moo int AUTO_INCREMENT PRIMARY KEY first; 

select * from penguins_copy; 
    # +-----+------+----------+ 
    # | moo | foo  | bar      | 
    # +-----+------+----------+ 
    # |   1 |    1 | skipper  | 
    # |   2 |    1 | skipper  | 
    # |   3 |    3 | kowalski | 
    # |   4 |    3 | kowalski | 
    # |   5 |    3 | kowalski | 
    # |   6 |    4 | rico     | 
    # +-----+------+----------+ 

Tổng hợp tối đa hoạt động theo chỉ số moo mới:

delete a from penguins_copy a left join( 
    select max(moo) myindex, foo, bar 
    from penguins_copy 
    group by foo, bar) b 
    on a.moo = b.myindex and 
    a.foo = b.foo and 
    a.bar = b.bar 
    where b.myindex IS NULL; 

#drop the extra column on the copied table 
alter table penguins_copy drop moo; 
select * from penguins_copy; 

#drop the first table and put the copy table back: 
drop table penguins; 
create table penguins select * from penguins_copy; 

quan sát và dọn dẹp

drop table penguins_copy; 
select * from penguins;
+------+----------+ 
| foo  | bar      | 
+------+----------+ 
|    1 | skipper  | 
|    3 | kowalski | 
|    4 | rico     | 
+------+----------+ 
    Elapsed: 1458.359 milliseconds 

Câu lệnh xóa SQL lớn đó đang làm gì?

Chim cánh cụt bảng có bí danh 'a' được nối lại trên một tập hợp con chim cánh cụt bảng được gọi là bí danh 'b'. Bảng bên phải 'b' là tập hợp con tìm dấu thời gian tối đa [hoặc max moo] được nhóm theo cột foo và bar. Điều này được khớp với bảng bên trái 'a'. (foo, bar, baz) bên trái có mỗi hàng trong bảng. Tập hợp con bên phải 'b' có một (maxtimestamp, foo, bar) được khớp với bên trái chỉ trên một cái là tối đa.

Mỗi hàng không phải là max có giá trị maxtimestamp của NULL. Lọc xuống các hàng NULL đó và bạn có một tập hợp tất cả các hàng được nhóm theo foo và thanh không phải là dấu thời gian mới nhất. Xóa những cái đó đi.

Tạo một bản sao lưu của bảng trước khi bạn chạy này.

Ngăn chặn vấn đề này không bao giờ xảy ra nữa trên bảng này:

Nếu bạn làm điều này để làm việc, và nó sẽ dập tắt "hàng trùng lặp" của bạn. Tuyệt quá. Bây giờ hãy xác định một khóa duy nhất tổng hợp mới trên bảng của bạn (trên hai cột đó) để ngăn không cho thêm các mục trùng lặp ở vị trí đầu tiên.

Giống như một hệ thống miễn dịch tốt, các hàng xấu thậm chí không được phép vào bảng tại thời điểm chèn. Sau đó, tất cả các chương trình thêm các bản sao sẽ phát đi sự phản đối của họ và khi bạn sửa chúng, vấn đề này sẽ không bao giờ xuất hiện nữa.


6
đánh giá hoàn toàn cho các tài liệu tham khảo Madagascar!
Michael Wiggins

1
Được đánh giá cao vì đây là một câu trả lời tuyệt vời và những gợi ý tuyệt vời, cảm ơn Eric đã làm việc tốt hơn bất kỳ câu trả lời nào khác ngoài kia.
johan

4
Lưu ý: Nếu bảng của bạn có IDcột tăng tự động thì ONmệnh đề chỉ cần khớp với IDcột, không có gì khác.
ebyrob

1
Tôi thích phần giải thích chi tiết nhưng ... Nếu tôi hiểu chính xác, câu trả lời này sử dụng dấu thời gian để phân biệt giữa các bản ghi. Theo nghĩa đó, hồ sơ không trùng lặp. Điều gì sẽ xảy ra nếu bạn không có dấu thời gian để phân biệt giữa các bản ghi, tức là tất cả các cols đều giống nhau cho 2 bản ghi trở lên?
Rsc Rsc

1
@RscRsc Nếu bạn không có cột dấu thời gian hoặc chỉ mục duy nhất để áp dụng tổng hợp tối đa thì có vẻ như bạn phải sao chép bảng, thêm chỉ mục duy nhất, áp dụng câu lệnh xóa, sau đó thay thế bảng đã sao chép trở lại ban đầu . Tôi đã thay đổi câu trả lời để phản ánh những hướng dẫn này.
Eric Leschinski

16

Sau khi tự mình xử lý vấn đề này, trên một cơ sở dữ liệu khổng lồ, tôi hoàn toàn không ấn tượng với hiệu suất của bất kỳ câu trả lời nào khác. Tôi muốn chỉ giữ hàng trùng lặp mới nhất và xóa phần còn lại.

Trong câu lệnh một truy vấn, không có bảng tạm thời, điều này làm việc tốt nhất với tôi,

DELETE e.*
FROM employee e
WHERE id IN
 (SELECT id
   FROM (SELECT MIN(id) as id
          FROM employee e2
          GROUP BY first_name, last_name
          HAVING COUNT(*) > 1) x);

Nhắc nhở duy nhất là tôi phải chạy truy vấn nhiều lần, nhưng ngay cả với điều đó, tôi thấy nó hoạt động tốt hơn cho tôi so với các tùy chọn khác.


1
Giải pháp thực dụng! Làm việc cho tôi - khoảng 20 giây cho một bảng innodb 2m + hàng. Có lần tôi đã sử dụng nó một vài lần và bị hạ một vài người phạm tội với số lượng trùng lặp cao, đã hoàn thành công việc một cách thủ công.
Troy Wray

1
Làm việc cho tôi trong một lần quét, tuyệt vời!
Murwa

Nó phải được thực thi nhiều lần nếu các bản sao cho bất kỳ cột nào lớn hơn 2 lần
PayteR

@PayteR đã được nêu trong câu trả lời, "Nhắc nhở duy nhất là tôi phải chạy truy vấn nhiều lần"
seaders

13

Điều này dường như luôn luôn làm việc cho tôi:

CREATE TABLE NoDupeTable LIKE DupeTable; 
INSERT NoDupeTable SELECT * FROM DupeTable group by CommonField1,CommonFieldN;

Mà giữ ID thấp nhất trên mỗi bản sao và phần còn lại của các bản ghi không bị lừa.

Tôi cũng đã thực hiện các thao tác sau để vấn đề dupe không còn xảy ra sau khi xóa:

CREATE TABLE NoDupeTable LIKE DupeTable; 
Alter table NoDupeTable Add Unique `Unique` (CommonField1,CommonField2);
INSERT IGNORE NoDupeTable SELECT * FROM DupeTable;

Nói cách khác, tôi tạo một bản sao của bảng đầu tiên, thêm một chỉ mục duy nhất vào các trường mà tôi không muốn sao chép và sau đó thực hiện một mục Insert IGNOREcó lợi thế là không thất bại như bình thườngInsert lần đầu tiên nó cố gắng thêm một bản ghi trùng lặp dựa trên hai trường và bỏ qua mọi bản ghi như vậy.

Di chuyển fwd không thể tạo bất kỳ bản ghi trùng lặp dựa trên hai trường đó.


1
Bạn sẽ không cần một ORDER BYtrong SELECTđể chắc chắn bản ghi nào thực sự làm được nó NoDupeTable?
ebyrob

@wiserob Tôi tin trừ khi có hướng dẫn khác, nó sẽ chọn ID thấp nhất nếu không có các tiêu chí khác. Tất nhiên là ORDER by ID Asckhông thể làm tổn thương nên tôi sẽ chỉnh sửa câu trả lời của mình hàng tháng.
dùng3649739

@itherrob Xin lỗi tôi xấu. Đặt hàng bởi sẽ không làm việc trong lựa chọn này theo kiến ​​thức của tôi. Một đơn hàng ở cuối phần chọn sẽ chỉ sắp xếp các bản sao được tìm thấy bởi ID thấp nhất được tìm thấy trong mỗi cặp. Thay phiên, bạn có thể làm một Select Max(ID)và sau đó Order by Max(ID)tất cả những gì sẽ làm là đảo ngược thứ tự của chèn. Để lấy ID cao nhất sẽ yêu cầu tôi tin rằng một tham gia chọn phức tạp hơn, bất kể bạn đặt hàng ở trên như thế nào, bạn sẽ lấy các giá trị trường từ ID thấp hơn.
dùng3649739

Trên thực tế, không chắc chắn những gì tôi đã suy nghĩ với thứ tự. Bạn chắc chắn muốn MAX(ID)hay MIN(ID)và tên cột thay vì *trong SELECT FROM DupeTabletuy nhiên, nếu không bạn sẽ chỉ nhận được một trong những ID's một cách ngẫu nhiên. Trong thực tế, nhiều SQL và thậm chí nghiêm ngặt của MySQL yêu cầu gọi một hàm tổng hợp trên mỗi cột không được chỉ định trong GROUP BYmệnh đề.
ebyrob

@itherrob Khi kiểm tra Max (ID) Min (ID) không làm gì ngoài việc trả lại ID của bản ghi Max hoặc Mind. Trong mỗi trường hợp lấy các hồ sơ giống nhau. Vì vậy, nếu tôi có hai bản ghi với các trường ID,First,Last,Notesvà bản ghi 1,Bob,Smith,NULL2,Bob,Smith,Arrearssau đó thực hiện SELECT *Max(ID), First,Last,Notes FROM DupeTable group by First,Lastcả hai sẽ trả về cùng một bản ghi, ngoại trừ với một ID khác. Tối đa (ID) sẽ trở lại 2,Bob,Smith,NULLvà Min (ID) sẽ trở lại 1,Bob,Smith,NULL. Để có được bản ghi thứ hai với 'Arrears' trong các ghi chú, tôi cần phải tham gia.
dùng3649739

7

Các công việc sau đây cho tất cả các bảng

CREATE TABLE `noDup` LIKE `Dup` ;
INSERT `noDup` SELECT DISTINCT * FROM `Dup` ;
DROP TABLE `Dup` ;
ALTER TABLE `noDup` RENAME `Dup` ;

6

Đây là một câu trả lời đơn giản:

delete a from target_table a left JOIN (select max(id_field) as id, field_being_repeated  
    from target_table GROUP BY field_being_repeated) b 
    on a.field_being_repeated = b.field_being_repeated
      and a.id_field = b.id_field
    where b.id_field is null;

Đó là một câu trả lời hay, ngoại trừ một lỗi nhỏand a.id_field = b.id
Vikrant Goel

Các LEFT JOINđể bchỉ cần so sánh b.id= a.id_fieldgiả sử field_idlà một ID duy nhất tự động tăng. Thế a.field_being_repeated = b.field_being_repeatedlà ngoại. (cũng b.id_fieldkhông tồn tại trong truy vấn này b.id.
ebyrob 10/11/2016

6

Công việc này để tôi xóa hồ sơ cũ:

delete from table where id in 
(select min(e.id)
    from (select * from table) e 
    group by column1, column2
    having count(*) > 1
); 

Bạn có thể thay thế min (e.id) thành max (e.id) để xóa các bản ghi mới nhất.


5
delete p from 
product p
inner join (
    select max(id) as id, url from product 
    group by url 
    having count(*) > 1
) unik on unik.url = p.url and unik.id != p.id;

1
Tôi thấy rằng một giải pháp hiệu quả hơn nhiều so với các giải pháp trên
Christian Butzke

5

Tôi tìm giải pháp của Werner ở trên là tiện lợi nhất vì nó hoạt động bất kể sự hiện diện của khóa chính, không gây rối với các bảng, sử dụng sql đơn giản trong tương lai, là điều rất dễ hiểu.

Như tôi đã nói trong nhận xét của mình, giải pháp đó chưa được giải thích chính xác. Vì vậy, đây là của tôi, dựa trên nó.

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.


4

Quy trình này sẽ loại bỏ tất cả các bản sao (bao gồm bội số) trong một bảng, giữ bản sao cuối cùng. Đây là một phần mở rộng của Truy xuất bản ghi cuối cùng trong mỗi nhóm

Hy vọng điều này hữu ích cho ai đó.

DROP TABLE IF EXISTS UniqueIDs;
CREATE Temporary table UniqueIDs (id Int(11));

INSERT INTO UniqueIDs
    (SELECT T1.ID FROM Table T1 LEFT JOIN Table T2 ON
    (T1.Field1 = T2.Field1 AND T1.Field2 = T2.Field2 #Comparison Fields 
    AND T1.ID < T2.ID)
    WHERE T2.ID IS NULL);

DELETE FROM Table WHERE id NOT IN (SELECT ID FROM UniqueIDs);

4

Một cách dễ dàng khác ... sử dụng CẬP NHẬT IGNORE:

Bạn phải sử dụng một chỉ mục trên một hoặc nhiều cột (loại chỉ mục). Tạo một cột tham chiếu tạm thời mới (không phải là một phần của chỉ mục). Trong cột này, bạn đánh dấu các đơn vị bằng cách cập nhật nó bằng mệnh đề bỏ qua. Từng bước một:

Thêm một cột tham chiếu tạm thời để đánh dấu các đơn vị:

ALTER TABLE `yourtable` ADD `unique` VARCHAR(3) NOT NULL AFTER `lastcolname`;

=> điều này sẽ thêm một cột vào bảng của bạn.

Cập nhật bảng, cố gắng đánh dấu mọi thứ là duy nhất, nhưng bỏ qua các lỗi có thể do sự cố khóa trùng lặp (hồ sơ sẽ bị bỏ qua):

UPDATE IGNORE `yourtable` SET `unique` = 'Yes' WHERE 1;

=> bạn sẽ thấy các bản ghi trùng lặp của mình sẽ không được đánh dấu là duy nhất = 'Có', nói cách khác, chỉ một trong mỗi bộ bản ghi trùng lặp sẽ được đánh dấu là duy nhất.

Xóa mọi thứ không phải là duy nhất:

DELETE * FROM `yourtable` WHERE `unique` <> 'Yes';

=> Điều này sẽ loại bỏ tất cả các hồ sơ trùng lặp.

Thả cột ...

ALTER TABLE `yourtable` DROP `unique`;

Tôi nghĩ rằng đây là giải pháp tốt nhất bởi vì nó không gây rối với các bảng và nó sử dụng sql đơn giản. Một điều duy nhất cần được làm rõ: uniquecột PHẢI được thêm vào một ràng buộc duy nhất cùng với các cột hiện đang được sao chép, nếu không thì toàn bộ điều này không hoạt động vì SET unique= 'Có' sẽ không bao giờ thất bại.
xtian

Cũng cần lưu ý rằng đó uniquelà một từ khóa mysql. Vì vậy, nó phải có backticks (như đã được hiển thị chính xác). Sử dụng một từ khác cho cột có thể thuận tiện hơn.
Torsten

2

Xóa các bản sao trên bảng MySQL là một vấn đề phổ biến, thường đi kèm với các nhu cầu cụ thể. Trong trường hợp có ai quan tâm, tại đây ( Xóa các hàng trùng lặp trong MySQL ) Tôi giải thích cách sử dụng bảng tạm thời để xóa các bản sao MySQL một cách đáng tin cậy và nhanh chóng, cũng hợp lệ để xử lý các nguồn dữ liệu lớn (với các ví dụ cho các trường hợp sử dụng khác nhau).

Ali , trong trường hợp của bạn, bạn có thể chạy một cái gì đó như thế này:

-- create a new temporary table
CREATE TABLE tmp_table1 LIKE table1;

-- add a unique constraint    
ALTER TABLE tmp_table1 ADD UNIQUE(sid, title);

-- scan over the table to insert entries
INSERT IGNORE INTO tmp_table1 SELECT * FROM table1 ORDER BY sid;

-- rename tables
RENAME TABLE table1 TO backup_table1, tmp_table1 TO table1;

0
delete from `table` where `table`.`SID` in 
    (
    select t.SID from table t join table t1 on t.title = t1.title  where t.SID > t1.SID
)

Điều này tạo ra Lỗi SQL (1093) trên một số cấu hình và phiên bản của MySQL.
ebyrob

0

Câu trả lời của Love @ eric nhưng dường như không hoạt động nếu bạn có một bàn thực sự lớn (Tôi sẽ nhận được The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET MAX_JOIN_SIZE=# if the SELECT is okaykhi tôi cố gắng chạy nó). Vì vậy, tôi đã giới hạn truy vấn tham gia chỉ xem xét các hàng trùng lặp và tôi đã kết thúc với:

DELETE a FROM penguins a
    LEFT JOIN (SELECT COUNT(baz) AS num, MIN(baz) AS keepBaz, foo
        FROM penguins
        GROUP BY deviceId HAVING num > 1) b
        ON a.baz != b.keepBaz
        AND a.foo = b.foo
    WHERE b.foo IS NOT NULL

Mệnh đề WHERE trong trường hợp này cho phép MySQL bỏ qua bất kỳ hàng nào không có bản sao và cũng sẽ bỏ qua nếu đây là phiên bản đầu tiên của bản sao để chỉ các bản sao tiếp theo sẽ bị bỏ qua. Thay đổi MIN(baz)để MAX(baz)giữ phiên bản cuối cùng thay vì lần đầu tiên.


0

Điều này làm việc cho các bảng lớn:

 CREATE Temporary table duplicates AS select max(id) as id, url from links group by url having count(*) > 1;

 DELETE l from links l inner join duplicates ld on ld.id = l.id WHERE ld.id IS NOT NULL;

Để xóa thay đổi cũ nhất max(id)thànhmin(id)


0

Điều này ở đây sẽ làm cho cột column_namethành một khóa chính và trong khi đó, bỏ qua tất cả các lỗi. Vì vậy, nó sẽ xóa các hàng với giá trị trùng lặp cho column_name.

ALTER IGNORE TABLE `table_name` ADD PRIMARY KEY (`column_name`);

Như đã lưu ý trong các ý kiến ​​cho câu trả lời trước đó, điều này không còn hoạt động trong 5.7.
Barmar

0

Tôi nghĩ rằng điều này sẽ hoạt động bằng cách sao chép bảng và làm trống bảng sau đó chỉ đưa các giá trị riêng biệt vào đó nhưng vui lòng kiểm tra lại trước khi thực hiện trên một lượng lớn dữ liệu.

Tạo một bản sao của bảng của bạn

tạo bảng temp_table như oldtablename; chèn temp_table chọn * từ oldtablename;

Làm trống bảng gốc của bạn

XÓA * từ oldtablename;

Sao chép tất cả các giá trị riêng biệt từ bảng đã sao chép trở lại bảng gốc của bạn

XÁC NHẬN oldtablename CHỌN * từ nhóm temp_table theo tên, họ, dob

Xóa bảng tạm thời của bạn.

Bảng thả temp_table

Bạn cần nhóm theo các trường aLL mà bạn muốn giữ riêng biệt.


0
DELETE T2
FROM   table_name T1
JOIN   same_table_name T2 ON (T1.title = T2.title AND T1.ID <> T2.ID)

nó không hoạt động theo yêu cầu của bạn, xin vui lòng bạn có thể cải thiện nó?
Samir Guiderk

0

đây là cách tôi thường loại bỏ trùng lặp

  1. thêm một cột tạm thời, đặt tên cho nó bất cứ điều gì bạn muốn (tôi sẽ gọi là hoạt động)
  2. nhóm theo các trường mà bạn nghĩ không nên trùng lặp và đặt hoạt động của chúng thành 1, nhóm theo sẽ chỉ chọn một trong các giá trị trùng lặp (sẽ không chọn trùng lặp) cho các cột đó
  3. xóa những cái không hoạt động
  4. thả cột hoạt động
  5. tùy chọn (nếu phù hợp với mục đích của bạn), hãy thêm chỉ mục duy nhất cho các cột đó để không bị trùng lặp nữa

-2

Bạn chỉ có thể sử dụng mệnh đề DISTINCT để chọn danh sách "đã dọn sạch" (và đây là một ví dụ rất dễ hiểu về cách thực hiện điều đó).


Làm thế nào mà trả lời câu hỏi? Sử dụng DISTINCTbạn mất bất kỳ thông tin nào về các bản sao bạn có thể có ở nơi đầu tiên. Bạn có thể chỉ ra một cách để xóa các bản sao bằng cách sử dụng nó?
luk2302

-3

Nó có thể hoạt động nếu bạn đếm chúng, và sau đó thêm một giới hạn cho truy vấn xóa của bạn chỉ để lại một truy vấn không?

Ví dụ: nếu bạn có hai hoặc nhiều hơn, hãy viết truy vấn của bạn như thế này:

DELETE FROM table WHERE SID = 1 LIMIT 1;

-5

Chỉ có một vài bước cơ bản khi xóa dữ liệu trùng lặp khỏi bảng của bạn:

  • Sao lưu bảng của bạn!
  • Tìm các hàng trùng lặp
  • Xóa các hàng trùng lặp

Dưới đây là hướng dẫn đầy đủ: https://blog.teamsql.io/deleting-d repeatate-data-3541485b3473


Nó hoạt động nếu chỉ có id duy nhất khác nhau. E sader sadece benzersiz id farklı ise de bu işe yarar mı?
Andrew

Theo mặc định, phương thức được mô tả ở đây không hoạt động đối với các phiên bản MySQL> 5.7.5. Điều này là do việc xử lý ONLY_FULL_GROUP_BY. Xem tại đây: dev.mysql.com/doc/refman/5.7/en/group-by-handling.html
delatbabel
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.