วิธีการลบข้อมูลที่ซ้ำกันในตาราง MySQL?


158

ฉันต้องการDELETEแถวที่ซ้ำกันสำหรับ sid ที่ระบุบนMySQLตาราง

ฉันจะทำสิ่งนี้กับแบบสอบถาม SQL ได้อย่างไร

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

บางอย่างเช่นนี้ แต่ฉันไม่รู้จะทำอย่างไร


คุณจำเป็นต้องทำเพียงครั้งเดียวหรือทำตลอดเวลา?
Billy ONeal

ระเบียนที่มีระเบียนที่ซ้ำกันทั้งหมดมีข้อมูลเหมือนกันหรือส่วนที่เหลือของเขตข้อมูลนั้นแตกต่างกันหรือไม่? หากคุณมีตัวเลือกแรกคุณสามารถลบระเบียนทั้งหมด แต่อย่างใดอย่างหนึ่งถ้าคุณมีตัวเลือกที่สองคุณจะกำหนดระเบียนที่คุณต้องการเก็บอย่างไร
rael_kid

@Lex ตัวเลือกแรก @ ฉันต้องการทำตลอดเวลา
Ali Demirci

1
ทำซ้ำที่เป็นไปได้ของการลบแถวที่ซ้ำกันใน MySQL
Basilevs

1
มีหลายสิ่งหลายอย่างที่เปลี่ยนแปลงไปใน MySQL เวอร์ชั่นต่างๆ ตรวจสอบเวอร์ชัน MySQL ของคุณอย่างถี่ถ้วนก่อนกระโจนลงสู่เส้นทางของโซลูชันใด ๆ
delatbabel

คำตอบ:


215

สิ่งนี้จะลบรายการที่ซ้ำกันโดยไม่ต้องสร้างตารางใหม่

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

หมายเหตุ: ทำงานได้ดีถ้าดัชนีพอดีกับหน่วยความจำ


26
ประกาศ: นี่จะเก็บระเบียนที่ซ้ำกันที่เก่าแก่ที่สุดและจะลบระเบียนที่ใหม่กว่า ALTER IGNOREหากคุณต้องการที่จะเก็บใหม่ล่าสุดที่คุณไม่สามารถทำเช่นนี้กับ
Haralan Dobrev

9
ดูเหมือนจะไม่ทำงานกับ InnoDB ฉันวิ่งALTER TABLE foo ENGINE MyISAMไปรอบ ๆ มันเปลี่ยนเครื่องยนต์หลัง
Martin

13
สิ่งนี้อาจล้มเหลวใน MySQL> 5.5 หากเป็นเช่นนั้นให้ใช้ "set session old_alter_table = 1;" และ "set เซสชั่น old_alter_table = 0;" ก่อนและหลังคำแถลง
chillitom


2
@delatbabel เหตุผลในการคัดค้านจะได้รับในหน้าเว็บที่คุณเชื่อมโยง
Barmar

133

สมมติว่าคุณมีตารางemployeeโดยมีคอลัมน์ต่อไปนี้:

employee (first_name, last_name, start_date)

วิธีลบแถวด้วยfirst_nameคอลัมน์ซ้ำ:

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

1
ระเบียนที่เหลือจะมี ID สูงสุดหรือต่ำสุดในกลุ่มที่ซ้ำกัน
Frozen Flame

บันทึกที่เหลือจะมี ID ขั้นต่ำเพราะมันเป็นเพียงคนเดียวที่ไม่ได้ประชุมสภาพที่จะลบ
ปาโบลเกร์เรโร

1
ดูเหมือนว่าการเข้าร่วมemployeeกับตัวเองสำหรับการจับคู่ดัชนีและการ>ตรวจสอบดัชนีจะช้าสำหรับตารางขนาดใหญ่ มันจะไม่ดีกว่าที่จะSELECT MAX(ID) FROM t GROUP BY uniqueแล้วJOINจะตรงกับIDการMAX(ID)?
ebyrob

1
คำตอบที่ดี! บันทึกเวลาของฉัน!
Nesar

56

การติดตามลบรายการที่ซ้ำกันสำหรับ SID-s ทั้งหมดไม่ใช่เพียงรายการเดียว

พร้อมโต๊ะ temp

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

DROP TABLE table;
RENAME TABLE table_temp TO table;

เนื่องจากtemp_tableถูกสร้างขึ้นใหม่จึงไม่มีดัชนี คุณจะต้องสร้างใหม่หลังจากลบรายการที่ซ้ำ คุณสามารถตรวจสอบดัชนีที่คุณมีในตารางด้วยSHOW INDEXES IN table

ไม่มีตารางชั่วคราว:

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
การจัดกลุ่มจะสร้างแถวผลลัพธ์เพียงแถวเดียวสำหรับการรวมกันของค่าของเขตข้อมูลที่คุณจัดกลุ่มตาม ดังนั้นรายการซ้ำจะถูกลบ
Kamil Szot

4
ฉันชอบวิธีแรกหรูหรามากเกินไปที่นี่! : B
AgelessEssence

1
@fiacre คุณสามารถปิดใช้งานการตรวจสอบ foreign key ชั่วคราวได้: stackoverflow.com/questions/15501673/…คุณอาจเสี่ยงต่อการลบแถวที่อ้างถึงในตารางอื่น ๆ แต่คุณสามารถควบคุมว่าระเบียนใดที่จะถูกเลือกไปยังตารางที่ลบข้อมูลโดยการเปลี่ยนแบบสอบถามSELECT * FROM table GROUP BY title, SID;ทุกอย่างขึ้นอยู่กับว่าคุณรู้ว่าคุณกำลังทำอะไรอยู่
Kamil Szot

1
@ahnbizcad คุณสามารถใช้ตารางชั่วคราวได้ แต่คุณจะต้องคัดลอกข้อมูลกลับจากตารางชั่วคราวไปยังตารางปกติ หากคุณใช้ตารางจริงคุณสามารถวางโต๊ะเก่าด้วยข้อมูลที่ซ้ำกันและเปลี่ยนชื่อโต๊ะใหม่โดยไม่ต้องใช้ชื่อที่ซ้ำกันแทนชื่อเดิม
Kamil Szot

1
วิธี "ไม่มีตาราง temp" ใกล้เคียงกับทางออกที่ดีที่สุด แต่ระวังการจัดการ ONLY_FULL_GROUP_BY ซึ่งเปลี่ยนไปใน MySQL 5.7.5: dev.mysql.com/doc/refman/5.7/en/group-by-handling.html ฉันได้รับสิ่งนี้ ทำงานโดยแทนที่ "SELECT id" ด้วย "SELECT ANY_VALUE (id) AS id"
delatbabel

53

การลบแถวที่ซ้ำกันใน MySQL แบบแทนที่ (สมมติว่าคุณมีคอลัมน์เวลาที่จะเรียงตาม) คำแนะนำแบบ:

สร้างตารางและแทรกแถว:

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)

ลบรายการที่ซ้ำ:

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)

คุณทำเสร็จแล้วแถวที่ซ้ำกันจะถูกลบออกแถวสุดท้ายจะถูกเก็บไว้

สำหรับผู้ที่ไม่มีการประทับเวลาหรือคอลัมน์ที่ไม่ซ้ำ

คุณไม่มีtimestampคอลัมน์หรือคอลัมน์ที่ไม่ซ้ำกันเพื่อจัดเรียง? คุณกำลังมีชีวิตอยู่ในสภาพเสื่อมโทรม คุณจะต้องทำตามขั้นตอนเพิ่มเติมเพื่อลบแถวที่ซ้ำกัน

สร้างตารางเพนกวินและเพิ่มบางแถว

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     | 
    # +------+----------+ 

ทำโคลนของตารางแรกและคัดลอกลงในมัน

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     | 
    # +-----+------+----------+ 

ผลรวมสูงสุดจะทำงานกับดัชนีหมู่ใหม่:

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; 

สังเกตและทำความสะอาด

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

คำสั่งลบ SQL ขนาดใหญ่กำลังทำอะไร

เพนกวินบนโต๊ะที่มีนามแฝง 'a' ถูกรวมเข้าด้วยกันบนเซตย่อยของเพนกวินบนโต๊ะที่ชื่อ alias 'b' ตารางด้านขวา 'b' ซึ่งเป็นชุดย่อยจะพบการประทับเวลาสูงสุด [หรือ max moo] จัดกลุ่มตามคอลัมน์ foo และแถบ ตรงกับตารางด้านซ้ายมือ 'a' (foo, bar, baz) ด้านซ้ายมีทุกแถวในตาราง เซตย่อยทางขวา 'b' มี (maxtimestamp, foo, bar) ซึ่งจับคู่กับซ้ายเฉพาะอันที่เป็นสูงสุด

ทุกแถวที่ไม่ใช่ max นั้นมีค่า maxtimestamp เป็น NULL กรองลงในแถว NULL เหล่านั้นและคุณมีชุดของแถวทั้งหมดที่จัดกลุ่มตาม foo และแถบที่ไม่ใช่ baz การประทับเวลาล่าสุด ลบรายการเหล่านั้น

สำรองข้อมูลของตารางก่อนที่จะเรียกใช้

ป้องกันปัญหานี้ไม่ให้เกิดขึ้นอีกครั้งในตารางนี้:

หากคุณได้รับสิ่งนี้ในการทำงานและมันดับไฟ "แถวที่ซ้ำกัน" ของคุณ ยิ่งใหญ่ ตอนนี้กำหนดคีย์ผสมใหม่ที่ไม่ซ้ำกันในตารางของคุณ (ในสองคอลัมน์เหล่านั้น) เพื่อป้องกันการเพิ่มรายการที่ซ้ำกันเพิ่มเติมตั้งแต่แรก

เช่นเดียวกับระบบภูมิคุ้มกันที่ดีแถวที่ไม่ดีไม่ควรได้รับอนุญาตให้เข้าสู่ตารางในเวลาที่ใส่ หลังจากนั้นทุกโปรแกรมที่เพิ่มรายการซ้ำจะออกอากาศการประท้วงและเมื่อคุณแก้ไขปัญหานี้จะไม่เกิดขึ้นอีก


6
ประเมินอัตราหมดจดสำหรับการอ้างอิงมาดากัสการ์!
Michael Wiggins

1
ให้คะแนนตั้งแต่นี้เป็นคำตอบที่ดีและคำแนะนำที่ดีขอบคุณ Eric ทำงานได้ดีกว่าคำตอบอื่น ๆ
โจฮัน

4
หมายเหตุ: หากตารางของคุณมีIDคอลัมน์เพิ่มอัตโนมัติONคำสั่งจะต้องตรงกับIDคอลัมน์เท่านั้นไม่มีอะไรอื่น
ebyrob

1
ฉันชอบคำอธิบายโดยละเอียด แต่ ... ถ้าฉันเข้าใจถูกต้องคำตอบนี้ใช้การประทับเวลาเพื่อแยกความแตกต่างระหว่างบันทึก ในกรณีดังกล่าวบันทึกจะไม่ซ้ำกัน เกิดอะไรขึ้นถ้าคุณไม่มีการประทับเวลาที่จะแยกแยะความแตกต่างระหว่างระเบียนเช่น cols ทั้งหมดจะเหมือนกันสำหรับ 2 หรือมากกว่าบันทึก
Rsc Rsc

1
@RscRsc หากคุณไม่มีคอลัมน์ประทับเวลาหรือดัชนีที่ไม่ซ้ำกันเพื่อใช้การรวมสูงสุดแล้วดูเหมือนว่าคุณต้องทำซ้ำตารางเพิ่มดัชนีที่ไม่ซ้ำกันใช้คำสั่งลบแล้วแทนที่ตาราง coped กลับไปที่เดิม . ฉันเปลี่ยนคำตอบเพื่อสะท้อนถึงคำแนะนำเหล่านี้
Eric Leschinski

16

หลังจากพบปัญหานี้ด้วยตนเองบนฐานข้อมูลขนาดใหญ่ฉันไม่ประทับใจอย่างสมบูรณ์กับประสิทธิภาพของคำตอบอื่น ๆ ฉันต้องการเก็บเฉพาะแถวที่ซ้ำกันล่าสุดและลบส่วนที่เหลือ

ในคำสั่งแบบค้นหาเดียวโดยไม่มีตารางชั่วคราวสิ่งนี้ทำงานได้ดีที่สุดสำหรับฉัน

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);

ข้อแม้เดียวคือฉันต้องเรียกใช้แบบสอบถามหลายครั้ง แต่ถึงอย่างนั้นฉันก็พบว่ามันใช้งานได้ดีกว่าตัวเลือกอื่น ๆ


1
วิธีแก้ปัญหาในทางปฏิบัติ! ทำงานให้ฉัน - ประมาณ 20 วินาทีสำหรับตาราง innodb 2m + แถว เมื่อฉันใช้มันสองสามครั้งและลงไปยังผู้ที่กระทำผิดสองสามครั้งที่มีจำนวนซ้ำกันให้ทำงานด้วยตนเองให้เสร็จ
Troy Wray

1
ทำงานให้ฉันในการกวาดครั้งเดียวยอดเยี่ยม!
Murwa

จะต้องดำเนินการหลายครั้งหากมีการทำซ้ำสำหรับคอลัมน์ใด ๆ ที่มากกว่า 2x
PayteR

@PayteR ที่ระบุไว้ในคำตอบ "ข้อแม้เพียงอย่างเดียวคือฉันต้องเรียกใช้แบบสอบถามหลายครั้ง"
seaders

13

ดูเหมือนว่าจะใช้ได้สำหรับฉันเสมอ:

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

ซึ่งจะเก็บ ID ที่ต่ำที่สุดในแต่ละรายการที่ซ้ำซ้อนและส่วนที่เหลือของรายการที่ไม่ใช่รายการที่ซ้ำกัน

ฉันได้ทำสิ่งต่อไปนี้เพื่อไม่ให้เกิดปัญหากับดักอีกต่อไปหลังจากการลบ:

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

กล่าวอีกนัยหนึ่งฉันสร้างที่ซ้ำกันของตารางแรกเพิ่มดัชนีที่ไม่ซ้ำกันในเขตข้อมูลที่ฉันไม่ต้องการให้ซ้ำกันแล้วทำสิ่งInsert IGNOREที่มีข้อได้เปรียบที่ไม่ล้มเหลวเหมือนปกติInsertในครั้งแรกที่พยายามเพิ่ม ระเบียนที่ซ้ำกันโดยยึดตามสองเขตข้อมูลและไม่สนใจระเบียนดังกล่าว

การย้าย fwd เป็นไปไม่ได้ที่จะสร้างระเบียนที่ซ้ำกันตามสองฟิลด์เหล่านั้น


1
คุณไม่จำเป็นต้องมีORDER BYในSELECTเพื่อให้แน่ใจว่าบันทึกใดที่ทำให้มันเป็นจริงNoDupeTable?
ebyrob

@ebyrob ฉันเชื่อว่านอกจากจะได้รับคำแนะนำเป็นอย่างอื่นแล้วมันจะเลือก ID ต่ำที่สุดโดยไม่มีเงื่อนไขอื่น ๆ แน่นอนว่าORDER by ID Ascไม่สามารถเจ็บได้ดังนั้นฉันจะแก้ไขคำตอบของฉันได้อย่างไรก็ตาม
user3649739

@ebyrob ขอโทษฉันไม่ดี เรียงลำดับตามจะไม่ทำงานในตัวเลือกนี้สำหรับความรู้ของฉัน คำสั่งซื้อในตอนท้ายของการเลือกจะเรียงลำดับรายการซ้ำที่พบโดย ID ต่ำสุดที่พบในแต่ละคู่ อีกวิธีหนึ่งคุณสามารถทำSelect Max(ID)และจากนั้นOrder by Max(ID)แต่สิ่งที่จะทำคือการกลับคำสั่งของการแทรก หากต้องการคว้า ID ที่สูงที่สุดฉันต้องเชื่อว่าการเข้าร่วมเลือกที่ซับซ้อนยิ่งขึ้นไม่ว่าคุณจะสั่งซื้ออย่างไรคุณจะคว้าค่าฟิลด์จาก ID ที่ต่ำกว่า
user3649739

จริงๆแล้วไม่แน่ใจว่าสิ่งที่ฉันคิดด้วยคำสั่งโดย แน่นอนคุณต้องการMAX(ID)หรือMIN(ID)และชื่อคอลัมน์แทน*ในSELECT FROM DupeTableแต่มิฉะนั้นคุณก็จะได้รับหนึ่งในID's สุ่ม ในความเป็นจริง SQLs จำนวนมากและแม้แต่ MySQL ที่เข้มงวดต้องเรียกใช้ฟังก์ชันการรวมในแต่ละคอลัมน์ที่ไม่ได้ระบุไว้ในGROUP BYข้อ
ebyrob

@ebyrob เมื่อทดสอบ Max (ID) ขั้นต่ำ (ID) ไม่ทำอะไรเลยยกเว้นส่งคืน ID ของระเบียน Max หรือ Mind ในแต่ละกรณีคว้าบันทึกเดียวกัน ดังนั้นถ้าฉันมีสองระเบียนที่มีสาขาID,First,Last,Notesและมีการบันทึก1,Bob,Smith,NULLและ2,Bob,Smith,Arrearsจากนั้นทำSELECT *Max(ID), First,Last,Notes FROM DupeTable group by First,Lastทั้งสองจะกลับมาบันทึกเดียวกัน 1 ยกเว้นที่มีรหัสที่แตกต่างกัน แม็กซ์ (ID) จะกลับมา2,Bob,Smith,NULLและมิน (ID) 1,Bob,Smith,NULLจะกลับมา เพื่อให้ได้เร็กคอร์ดที่สองที่มี 'Arrears' ในโน้ตต้องเข้าร่วมฉันเชื่อว่า
user3649739

7

การทำงานต่อไปนี้สำหรับตารางทั้งหมด

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

6

นี่คือคำตอบง่ายๆ:

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;

มันเป็นคำตอบที่ดียกเว้นความผิดพลาดเล็กน้อยand a.id_field = b.id
Vikrant Goel

LEFT JOINเพื่อbเพียงต้องการที่จะเปรียบเทียบb.id= a.id_fieldสมมติว่าfield_idเป็นรหัสที่เพิ่มขึ้นรถยนต์ที่ไม่ซ้ำกัน เพื่อให้a.field_being_repeated = b.field_being_repeatedเป็นภายนอก (และb.id_fieldไม่มีอยู่ในข้อความค้นหานี้b.idด้วย
ebyrob

6

การทำงานนี้สำหรับฉันที่จะลบระเบียนเก่า:

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

คุณสามารถแทนที่ min (e.id) เป็น max (e.id) เพื่อลบระเบียนล่าสุด


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
ฉันพบว่าวิธีแก้ปัญหาที่มีประสิทธิภาพมากกว่าที่กล่าวไว้ข้างต้น
Christian Butzke

5

ฉันพบวิธีแก้ปัญหาของ Werner ด้านบนนั้นสะดวกที่สุดเพราะใช้ได้โดยไม่คำนึงถึงคีย์หลักไม่ยุ่งกับตารางใช้ตารางธรรมดาที่พิสูจน์ได้ในอนาคตเป็นที่เข้าใจได้มาก

ตามที่ระบุไว้ในความคิดเห็นของฉันโซลูชันนั้นยังไม่ได้อธิบายอย่างถูกต้อง ดังนั้นนี่คือของฉันขึ้นอยู่กับมัน

1) เพิ่มคอลัมน์บูลีนใหม่

alter table mytable add tokeep boolean;

2) เพิ่มข้อ จำกัด ในคอลัมน์ที่ซ้ำซ้อนและคอลัมน์ใหม่

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

3) ตั้งค่าคอลัมน์บูลีนเป็นจริง สิ่งนี้จะสำเร็จในแถวที่ซ้ำหนึ่งแถวเนื่องจากข้อ จำกัด ใหม่

update ignore mytable set tokeep = true;

4) ลบแถวที่ไม่ได้ทำเครื่องหมายเป็น tokeep

delete from mytable where tokeep is null;

5) วางคอลัมน์เพิ่ม

alter table mytable drop tokeep;

ฉันขอแนะนำให้คุณรักษาข้อ จำกัด ที่คุณเพิ่มไว้เพื่อป้องกันการซ้ำซ้อนใหม่ในอนาคต


4

ขั้นตอนนี้จะลบรายการที่ซ้ำกันทั้งหมด (รวมทวีคูณ) ในตารางโดยเก็บสำเนาที่ซ้ำกันล่าสุด นี่เป็นส่วนขยายของการดึงข้อมูลระเบียนสุดท้ายในแต่ละกลุ่ม

หวังว่านี่จะเป็นประโยชน์กับใครบางคน

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

อีกวิธีที่ง่าย ... ใช้อัปเดต IGNORE:

คุณต้องใช้ดัชนีในคอลัมน์อย่างน้อยหนึ่งคอลัมน์ (ดัชนีประเภท) สร้างคอลัมน์อ้างอิงชั่วคราวใหม่ (ไม่ใช่ส่วนหนึ่งของดัชนี) ในคอลัมน์นี้คุณทำเครื่องหมายเฉพาะในโดยอัปเดตด้วยละเว้นข้อ เป็นขั้นเป็นตอน:

เพิ่มคอลัมน์อ้างอิงชั่วคราวเพื่อทำเครื่องหมายของที่ไม่ซ้ำ:

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

=> จะเพิ่มคอลัมน์ในตารางของคุณ

อัปเดตตารางพยายามทำเครื่องหมายทุกอย่างว่าไม่ซ้ำใคร แต่ไม่สนใจข้อผิดพลาดที่เป็นไปได้เนื่องจากปัญหาคีย์ซ้ำ (บันทึกจะถูกข้าม):

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

=> คุณจะพบว่าระเบียนที่ซ้ำกันของคุณจะไม่ถูกทำเครื่องหมายเป็นไม่ซ้ำกัน = 'ใช่' ในคำอื่น ๆ เพียงหนึ่งระเบียนที่ซ้ำกันแต่ละชุดจะถูกทำเครื่องหมายว่าไม่ซ้ำกัน

ลบทุกอย่างที่ไม่ซ้ำกัน:

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

=> จะเป็นการลบระเบียนที่ซ้ำกันทั้งหมด

วางคอลัมน์ ...

ALTER TABLE `yourtable` DROP `unique`;

ฉันคิดว่านี่เป็นทางออกที่ดีที่สุดเพราะไม่ยุ่งกับตารางและใช้ sql แบบธรรมดาธรรมดา สิ่งหนึ่งที่ควรทำให้ชัดเจนคือ: uniqueคอลัมน์จะต้องถูกเพิ่มเข้าไปในข้อ จำกัด ที่ไม่ซ้ำกันพร้อมกับคอลัมน์ที่มีการทำซ้ำในปัจจุบันมิฉะนั้นสิ่งทั้งหมดจะไม่ทำงานเพราะ SET unique= 'ใช่' จะไม่ล้มเหลว
xtian

นอกจากนี้โปรดระวังด้วยว่าuniqueเป็นคำสำคัญ mysql ดังนั้นจึงต้องมีการตีกลับ (ตามที่แสดงแล้วอย่างถูกต้อง) การใช้คำอื่นสำหรับคอลัมน์อาจสะดวกกว่า
Torsten

2

การลบข้อมูลซ้ำซ้อนในตาราง MySQL เป็นปัญหาทั่วไปซึ่งมักมาพร้อมกับความต้องการเฉพาะ ในกรณีที่ทุกคนสนใจที่นี่ ( ลบแถวที่ซ้ำกันใน MySQL ) ฉันอธิบายวิธีการใช้ตารางชั่วคราวเพื่อลบข้อมูลซ้ำซ้อน MySQL ในวิธีที่เชื่อถือได้และรวดเร็วนอกจากนี้ยังสามารถจัดการแหล่งข้อมูลขนาดใหญ่ได้ (พร้อมตัวอย่างสำหรับกรณีการใช้งานที่แตกต่างกัน)

อาลีในกรณีของคุณคุณสามารถเรียกใช้อะไรเช่นนี้

-- 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
)

สิ่งนี้สร้างข้อผิดพลาดของ SQL (1093) ในการกำหนดค่าและรุ่นของ MySQL
ebyrob

0

คำตอบของ Love @ eric แต่ดูเหมือนจะไม่ทำงานถ้าคุณมีโต๊ะตัวใหญ่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 okayมาก ดังนั้นฉันจึง จำกัด แบบสอบถามการเข้าร่วมเพื่อพิจารณาเฉพาะแถวที่ซ้ำกันและฉันสิ้นสุดด้วย:

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

ส่วนคำสั่ง WHERE ในกรณีนี้อนุญาตให้ MySQL ละเว้นแถวที่ไม่มีการทำซ้ำและจะละเว้นหากนี่เป็นอินสแตนซ์แรกของการทำซ้ำดังนั้นการทำซ้ำที่ตามมาจะถูกละเว้น เปลี่ยนMIN(baz)เป็นMAX(baz)เก็บอินสแตนซ์สุดท้ายแทนอันแรก


0

ใช้งานได้กับตารางขนาดใหญ่:

 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;

เพื่อลบการเปลี่ยนแปลงที่เก่าแก่ที่สุดmax(id)ที่จะmin(id)


0

นี่จะทำให้คอลัมน์column_nameเป็นคีย์หลักและในขณะเดียวกันก็จะละเว้นข้อผิดพลาดทั้งหมด column_nameดังนั้นมันจะลบแถวที่มีค่าที่ซ้ำกันสำหรับ

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

ดังที่ระบุไว้ในความคิดเห็นต่อคำตอบก่อนหน้านี้ไม่สามารถใช้งานได้ใน 5.7
Barmar

0

ผมคิดว่านี้จะทำงานโดยการคัดลอกพื้นโต๊ะและล้างแล้วใส่เฉพาะค่าที่แตกต่างกันกลับเข้ามา แต่โปรดตรวจสอบอีกครั้งก่อนที่จะทำมันในข้อมูลจำนวนมาก

สร้างสำเนาของตาราง

สร้าง temp_table ของตารางเช่น oldtablename; แทรก temp_table เลือก * จาก oldtablename;

เปล่าตารางเดิมของคุณ

ลบ * จาก oldtablename;

คัดลอกค่าที่แตกต่างทั้งหมดจากตารางที่คัดลอกกลับไปยังตารางดั้งเดิมของคุณ

INSERT oldtablename * เลือกจากกลุ่ม temp_table โดยชื่อ, นามสกุล, วันเดือนปีเกิด

ลบตารางชั่วคราวของคุณ

temp_table Drop ตาราง

คุณจำเป็นต้องจัดกลุ่มตามเขตข้อมูลทั้งหมดที่คุณต้องการที่จะเก็บที่แตกต่างกัน


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

มันไม่ทำงานตามคำขอของคุณโปรดที่คุณสามารถปรับปรุงมันได้หรือไม่
Samir Guiderk

0

นี่คือวิธีที่ฉันมักจะกำจัดรายการที่ซ้ำกัน

  1. เพิ่มคอลัมน์ชั่วคราวชื่อมันสิ่งที่คุณต้องการ (ฉันจะดูเป็นงาน)
  2. กลุ่มตามเขตข้อมูลที่คุณคิดว่าไม่ควรจะซ้ำกันและการตั้งค่าการใช้งานของพวกเขา 1, การจัดกลุ่มโดยจะเลือกเพียงหนึ่งในค่าที่ซ้ำกัน (จะไม่เลือกที่ซ้ำกัน) สำหรับคอลัมน์ที่
  3. ลบคนที่มีศูนย์ที่ใช้งาน
  4. คอลัมน์แบบเลื่อนใช้งาน
  5. เลือก (ถ้าเหมาะกับวัตถุประสงค์ของคุณ), เพิ่มดัชนีที่ไม่ซ้ำสำหรับคอลัมน์เหล่านั้นไม่สามารถมีซ้ำกันอีกครั้ง

-2

คุณก็สามารถใช้คำสั่งแตกต่างกันไปเลือก "ทำความสะอาด" รายการ (และนี่เป็นตัวอย่างที่ง่ายมากในการที่จะทำเช่นนั้น)


นั่นจะตอบคำถามได้อย่างไร การใช้DISTINCTข้อมูลหลวม ๆ เกี่ยวกับรายการซ้ำที่คุณอาจมีในตอนแรก คุณสามารถแสดงวิธีการลบรายการที่ซ้ำกันโดยใช้หรือไม่
luk2302

-3

สามารถใช้งานได้ถ้าคุณนับพวกมันแล้วเพิ่มขีด จำกัด ให้กับคิวรีการลบที่เหลืออยู่

ตัวอย่างเช่นหากคุณมีสองคนขึ้นไปเขียนแบบสอบถามของคุณเช่นนี้:

DELETE FROM table WHERE SID = 1 LIMIT 1;

-5

มีเพียงไม่กี่ขั้นตอนพื้นฐานเมื่อลบข้อมูลที่ซ้ำกันออกจากตารางของคุณ:

  • สำรองโต๊ะของคุณ!
  • ค้นหาแถวที่ซ้ำกัน
  • ลบแถวที่ซ้ำกัน

นี่คือการกวดวิชาเต็ม: https://blog.teamsql.io/deleting-duplicate-data-3541485b3473


มันทำงานถ้าเพียง แต่แตกต่างกัน ID ไม่ซ้ำกัน Eger sadece benzersiz ID farklı ISE de bu ISE yarar MI?
แอนดรู

โดยค่าเริ่มต้นวิธีการอธิบายที่นี่ไม่ทำงานสำหรับรุ่น MySQL> 5.7.5 นี่เป็นเพราะการจัดการ ONLY_FULL_GROUP_BY ดูที่นี่: dev.mysql.com/doc/refman/5.7/en/group-by-handling.html
delatbabel
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.