Удаление повторяющихся строк из базы данных sqlite

92

У меня есть огромная таблица - 36 миллионов строк - в SQLite3. В этой очень большой таблице есть два столбца:

  • hash - текст
  • d - настоящий

Некоторые строки дублируются. То есть оба hashи dимеют одинаковые значения. Если два хэша идентичны, то значения d. Однако два одинаковых dне означают двух одинаковых hash.

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

Как это сделать быстрее всего?

Патчи
источник
Поместите ответы в блоки ответов. Позже вы можете принять свой ответ. Также см. Как работает принятие ответа?
jww 02

Ответы:

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

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

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

MaDa
источник
Не так элегантно, как простое изменение таблицы, я думаю, НО одна действительно хорошая вещь в вашем подходе заключается в том, что вы можете повторно запускать его столько раз, сколько захотите, не трогая / не уничтожая исходные данные, пока вы не будете полностью довольны результатами .
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()функция типа, но если она есть, вы также можете попробовать некоторые из перечисленных здесь подходов: Удалить повторяющиеся записи из таблицы SQL без первичного ключа

rsbarro
источник
+1, хотя не уверен, поддерживает ли sqlite delete <alias> from <table> <alias>синтаксис
Andomar