การลบแถวที่ซ้ำกันออกจากฐานข้อมูล sqlite


92

ฉันมีตารางขนาดใหญ่ - 36 ล้านแถว - ใน SQLite3 ในตารางขนาดใหญ่นี้มีสองคอลัมน์:

  • hash - ข้อความ
  • d - จริง

บางแถวซ้ำกัน นั่นคือทั้งสองhashและdมีค่าเหมือนกัน หากแฮชสองอันเหมือนกันค่าของd. อย่างไรก็ตามสองตัวที่เหมือนกันdไม่ได้หมายความว่าเหมือนกันสองhashตัว

ฉันต้องการลบแถวที่ซ้ำกัน ฉันไม่มีคอลัมน์คีย์หลัก

วิธีที่เร็วที่สุดในการทำคืออะไร?


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

คำตอบ:


122

คุณต้องมีวิธีแยกแยะแถว จากความคิดเห็นของคุณคุณสามารถใช้คอลัมน์ rowidพิเศษสำหรับสิ่งนั้น

ในการลบรายการที่ซ้ำกันโดยให้ต่ำที่สุดrowidต่อ(hash,d):

delete   from YourTable
where    rowid not in
         (
         select  min(rowid)
         from    YourTable
         group by
                 hash
         ,       d
         )

SQLite ไม่อนุญาตให้คุณเพิ่มคอลัมน์คีย์หลักใช่หรือไม่?
แพทช์

sqlite> alter table dist add id integer primary key autoincrement; Error: Cannot add a PRIMARY KEY column
แพทช์

น่าสนใจ! ส่วนที่คุณต้องการคือautoincrementแม้ว่าจะใช้งานได้หรือไม่ถ้าคุณไม่ใส่primary keyส่วน
Andomar

sqlite> alter table dist add id integer autoincrement; Error: near "autoincrement": syntax error แก้ไข: SQLite มีคอลัมน์หลอกประเภท "rowid" ที่อยู่ที่นั่นโดยอัตโนมัติฉันสามารถใช้สิ่งนี้ได้หรือไม่
แพทช์

1
delete from dist where rowid not in (select max(rowid) from dist group by hash); ปรากฏว่าทำได้จริง! ขอบคุณ.
แพทช์

5

ฉันเดาว่าวิธีที่เร็วที่สุดคือการใช้ฐานข้อมูลสำหรับมัน: เพิ่มตารางใหม่ที่มีคอลัมน์เดียวกัน แต่ด้วยข้อ จำกัด ที่เหมาะสม (ดัชนีเฉพาะในแฮช / คู่จริง?) วนซ้ำผ่านตารางเดิมและพยายามแทรกระเบียนใน ตารางใหม่โดยไม่สนใจข้อผิดพลาดในการละเมิดข้อ จำกัด (เช่นทำซ้ำต่อเมื่อมีการยกข้อยกเว้น)

จากนั้นลบตารางเก่าและเปลี่ยนชื่อตารางใหม่เป็นตารางเก่า


ไม่สวยหรูเหมือนแค่การปรับเปลี่ยนตาราง แต่สิ่งหนึ่งที่ดีจริงๆเกี่ยวกับแนวทางของคุณคือคุณสามารถเรียกใช้ซ้ำได้หลายครั้งเท่าที่คุณต้องการโดยไม่ต้องสัมผัส / ทำลายแหล่งข้อมูลจนกว่าคุณจะพอใจกับผลลัพธ์อย่างแท้จริง .
Adrian K

1

หากการเพิ่มคีย์หลักไม่ใช่ตัวเลือกวิธีการหนึ่งคือการจัดเก็บ DISTINCT ที่ซ้ำกันในตารางชั่วคราวลบระเบียนที่ซ้ำกันทั้งหมดจากตารางที่มีอยู่จากนั้นเพิ่มระเบียนกลับเข้าไปในตารางเดิมจากตารางชั่วคราว .

ตัวอย่างเช่น (เขียนสำหรับ SQL Server 2008 แต่เทคนิคเหมือนกันสำหรับฐานข้อมูลใด ๆ ):

DECLARE @original AS TABLE([hash] varchar(20), [d] float)
INSERT INTO @original VALUES('A', 1)
INSERT INTO @original VALUES('A', 2)
INSERT INTO @original VALUES('A', 1)
INSERT INTO @original VALUES('B', 1)
INSERT INTO @original VALUES('C', 1)
INSERT INTO @original VALUES('C', 1)

DECLARE @temp AS TABLE([hash] varchar(20), [d] float)
INSERT INTO @temp
SELECT [hash], [d] FROM @original 
GROUP BY [hash], [d]
HAVING COUNT(*) > 1

DELETE O
FROM @original O
JOIN @temp T ON T.[hash] = O.[hash] AND T.[d] = O.[d]

INSERT INTO @original
SELECT [hash], [d] FROM @temp

SELECT * FROM @original

ฉันไม่แน่ใจว่า sqlite มีROW_NUMBER()ฟังก์ชัน type หรือไม่ แต่ถ้าเป็นเช่นนั้นคุณสามารถลองใช้วิธีการบางอย่างที่ระบุไว้ที่นี่: ลบระเบียนที่ซ้ำกันจากตาราง SQL โดยไม่มีคีย์หลัก


+1 ไม่แน่ใจว่า sqlite รองรับdelete <alias> from <table> <alias>ไวยากรณ์หรือไม่
Andomar
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.