Видалення повторюваних рядків з бази даних sqlite


91

У мене є величезна таблиця - 36 мільйонів рядків - у SQLite3. У цій дуже великій таблиці є дві колонки:

  • hash - текст
  • d - справжній

Деякі рядки є дублікатами. Тобто обидва hashі dмають однакові значення. Якщо два хеші однакові, то значення значень також d. Однак два однакових dне означають двох однакових hash.

Я хочу видалити повторювані рядки. У мене немає стовпця первинного ключа.

Який найшвидший спосіб це зробити?


Будь ласка, розмістіть відповіді в блоках відповідей. Пізніше ви зможете прийняти власну відповідь. Також див. Як працює прийняття відповіді?
jww

Відповіді:


121

Вам потрібен спосіб розрізнення рядків. На основі вашого коментаря ви можете використовувати для цього спеціальний стовпець 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

Я думаю, найшвидшим було б використовувати саму базу даних для неї: додати нову таблицю з тими ж стовпцями, але з належними обмеженнями (унікальний індекс на хеш / реальну пару?), Перебирати вихідну таблицю та намагатися вставити записи в нову таблицю, ігноруючи помилки порушення обмежень (тобто продовжувати ітерацію, коли виникають винятки).

Потім видаліть стару таблицю та перейменуйте нову на стару.


Думаю, це не настільки елегантно, як просто змінити таблицю, АЛЕ одна дійсно хороша річ у вашому підході полягає в тому, що ви можете повторно запускати його стільки разів, скільки завгодно, не торкаючись / знищуючи вихідні дані, поки ви абсолютно не задоволені результатами .
Адріан К

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()типу, але якщо вона є, ви також можете спробувати деякі з перелічених тут підходів: Видалити повторювані записи з таблиці SQL без первинного ключа


+1, не впевнений, що sqlite підтримує delete <alias> from <table> <alias>синтаксис, хоча
Andomar
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.