วิธีค้นหารายการที่ซ้ำกันใน 2 คอลัมน์ไม่ใช่ 1


107

ฉันมีตารางฐานข้อมูล MySQL ที่มีสองคอลัมน์ที่ฉันสนใจ แต่ละคนสามารถมีรายการซ้ำกันได้ แต่ไม่ควรซ้ำกันโดยที่ทั้งคู่มีค่าเท่ากัน

stone_idสามารถมีรายการที่ซ้ำกันได้ตราบเท่าที่แต่ละupshargeชื่อไม่เหมือนกันและในทางกลับกัน แต่พูดเช่นstone_id= 412 และupcharge_title= "แซฟไฟร์" การรวมกันควรเกิดขึ้นเพียงครั้งเดียว

สิ่งนี้ใช้ได้:

stone_id = 412 upcharge_title = "sapphire"
stone_id = 412 upcharge_title = "ruby"

ไม่เป็นไร:

stone_id = 412 upcharge_title = "sapphire"
stone_id = 412 upcharge_title = "sapphire"

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

ฉันใช้ MySQL เวอร์ชัน 4.1.22

คำตอบ:


192

คุณควรตั้งค่าคีย์ผสมระหว่างสองฟิลด์ สิ่งนี้จะต้องใช้ stone_id และ upcharge_title ที่ไม่ซ้ำกันสำหรับแต่ละแถว

เท่าที่ค้นหารายการซ้ำที่มีอยู่ให้ลองทำดังนี้:

select   stone_id,
         upcharge_title,
         count(*)
from     your_table
group by stone_id,
         upcharge_title
having   count(*) > 1

ขอบคุณที่เลือกพวกเขา กรุณาช่วยบอกวิธีลบรายการที่ซ้ำกันได้ไหม (แต่ทิ้งไว้ 1 ชุด) ขอบคุณ !!
JD Isaacks

2
วิธีหนึ่งคือการดึงข้อมูลที่แตกต่างทั้งหมดและสร้างตารางขึ้นมาใหม่
Miyagi Coder

1
@ John Isaacks: หากไม่มีฟิลด์อื่นที่คุณสามารถแยกความแตกต่างได้ (เช่นฟิลด์ทั้งหมดซ้ำกัน) คุณจะต้องลบทั้งสองแถวและสร้างขึ้นใหม่ วิธีหนึ่งคือการคัดลอกรายการที่ซ้ำกันลงในสำเนาของตารางลบออกจากต้นฉบับและใส่แถวที่ไม่ซ้ำกันจากสำเนาอีกครั้ง
P Daddy

สิ่งนี้ใช้ไม่ได้กับ postgres 8.1 มีใครช่วยฉันหน่อยได้ไหม
Lennon

ขอบคุณมากลำดับที่คุณจัดกลุ่มตามเรื่องหรือไม่
Andrew

35

ฉันพบว่ามีประโยชน์ในการเพิ่มดัชนี unqiue โดยใช้ "ALTER IGNORE" ซึ่งจะลบรายการที่ซ้ำกันและบังคับใช้บันทึกที่ไม่ซ้ำกันซึ่งดูเหมือนคุณต้องการจะทำ ดังนั้นไวยากรณ์จะเป็น:

ALTER IGNORE TABLE `table` ADD UNIQUE INDEX(`id`, `another_id`, `one_more_id`);

สิ่งนี้ช่วยเพิ่มข้อ จำกัด ที่เป็นเอกลักษณ์ได้อย่างมีประสิทธิภาพซึ่งหมายความว่าคุณจะไม่มีระเบียนที่ซ้ำกันและ IGNORE จะลบรายการที่ซ้ำกันที่มีอยู่

คุณสามารถอ่านเพิ่มเติมเกี่ยวกับ eh ALTER IGNORE ได้ที่นี่: http://mediakey.dk/~cc/mysql-remove-duplicate-entries/

อัปเดต: ฉันได้รับแจ้งจาก @Inquisitive ว่าสิ่งนี้อาจล้มเหลวในเวอร์ชันของ MySql> 5.5:

มันล้มเหลวใน MySQL> 5.5 และบนโต๊ะ InnoDB และใน Percona เนื่องจากคุณสมบัติการสร้างดัชนีรวดเร็ว InnoDB ของพวกเขา [ http://bugs.mysql.com/bug.php?id=40344] ในกรณีนี้ให้รันก่อนset session old_alter_table=1จากนั้นคำสั่งดังกล่าวจะทำงานได้ดี

อัปเดต - ALTER IGNOREลบออกใน 5.7

จากเอกสาร

สำหรับ MySQL 5.6.17 ประโยค IGNORE จะเลิกใช้งานและการใช้งานจะสร้างคำเตือน IGNORE ถูกลบออกใน MySQL 5.7

หนึ่งใน MySQL dev ของให้ สองทางเลือก :

  • จัดกลุ่มตามช่องที่ไม่ซ้ำกันและลบตามที่เห็นด้านบน
  • สร้างตารางใหม่เพิ่มดัชนีเฉพาะใช้INSERT IGNOREเช่น:
CREATE TABLE duplicate_row_table LIKE regular_row_table;
ALTER TABLE duplicate_row_table ADD UNIQUE INDEX (id, another_id);
INSERT IGNORE INTO duplicate_row_table SELECT * FROM regular_row_table;
DROP TABLE regular_row_table;
RENAME TABLE duplicate_row_table TO regular_row_table;

แต่ขึ้นอยู่กับขนาดของโต๊ะของคุณสิ่งนี้อาจไม่สามารถใช้งานได้จริง


1
จริง แต่อย่างน้อยครั้งต่อไปที่คุณรู้ ฉันมีปัญหาเดียวกันและคิดว่าเป็นการดีที่จะแบ่งปันกับผู้อื่น
SeanDowney

ฉันแค่ล้อเล่นว่ามันมาสาย 3 ปีแล้ว ดีใจจริงๆที่คุณแบ่งปัน ดังนั้นการบวก 1.
JD Isaacks

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

+1 สำหรับคำตอบแม้จะช้าไป 2 ปี ฉันลบคีย์คอมโพสิตโดยไม่ได้ตั้งใจและนี่เป็นการช่วยชีวิต ขอบคุณ
ivcode

ฉันได้ลองใช้เทคนิคการค้นหาการทำซ้ำสองสามวิธีแล้วและไม่มีวิธีใดที่ง่ายและรวดเร็ว ขอบคุณสำหรับการแบ่งปันวิธีนี้
Kristjan O.


4

ในการค้นหารายการที่ซ้ำกัน:

select stone_id, upcharge_title from tablename group by stone_id, upcharge_title having count(*)>1

หากต้องการ จำกัด เพื่อหลีกเลี่ยงปัญหานี้ในอนาคตให้สร้างคีย์เฉพาะแบบผสมในสองฟิลด์นี้


1
ขอบคุณมากโปรดบอกวิธีลบรายการที่ซ้ำกันทั้งหมดยกเว้นรายการเดียว และฉันจะตั้งค่าคีย์คอมโพสิตใน phpmyadmin ได้อย่างไร ขอบคุณ!!!
JD Isaacks

3

อนึ่งข้อ จำกัด เฉพาะของคอมโพสิตบนโต๊ะจะป้องกันไม่ให้สิ่งนี้เกิดขึ้นตั้งแต่แรก

ALTER TABLE table
    ADD UNIQUE(stone_id, charge_title)

(นี่คือ T-SQL ที่ถูกต้องไม่แน่ใจเกี่ยวกับ MySQL)


1
ฉันคิดว่ามันได้ผล แต่ฉันจะไม่ทำจนกว่าฉันจะลบรายการที่ซ้ำกันออกก่อน ขอบคุณ.
JD Isaacks

1

โพสต์ SO นี้ช่วยฉัน แต่ฉันก็อยากรู้วิธีลบและเก็บหนึ่งในแถว ... นี่คือโซลูชัน PHP เพื่อลบแถวที่ซ้ำกันและเก็บไว้ (ในกรณีของฉันมีเพียง 2 คอลัมน์และอยู่ใน ฟังก์ชันสำหรับล้างการเชื่อมโยงหมวดหมู่ที่ซ้ำกัน)

$dupes = $db->query('select *, count(*) as NUM_DUPES from PRODUCT_CATEGORY_PRODUCT group by fkPRODUCT_CATEGORY_ID, fkPRODUCT_ID having count(*) > 1');
if (!is_array($dupes))
    return true;
foreach ($dupes as $dupe) {
    $db->query('delete from PRODUCT_CATEGORY_PRODUCT where fkPRODUCT_ID = ' . $dupe['fkPRODUCT_ID'] . ' and fkPRODUCT_CATEGORY_ID = ' . $dupe['fkPRODUCT_CATEGORY_ID'] . ' limit ' . ($dupe['NUM_DUPES'] - 1);
}

(จำกัด NUM_DUPES - 1) คือสิ่งที่รักษาแถวเดียว ...

ขอบคุณทุกคน


3
ALTER IGNORE TABLE table ADD UNIQUE INDEX index_name(stone_id, charge_title)จะลบแถวที่ซ้ำกันเหลือเพียงคู่เดียว
dev-null-dweller
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.