SQLite: удаляйте дубликаты, но сохраняйте одно и не дублирующиеся поля - PullRequest
0 голосов
/ 09 декабря 2018

У меня проблема, когда каким-то образом дублированные строки попали в базу данных, где определенный столбец дублирован.Я провел некоторое исследование и нашел посты типа этот , который работает, за исключением того, что удаляет ВСЕ строки, кроме одного из дубликатов.

Моя структура таблицы выглядит так:

  id    |  hints                        |
  208      episode=1&season=1&show=Name1
  209      episode=1&season=1&show=Name1
  210      episode=1&season=2&show=Name1
  211      episode=1&season=2&show=Name1
  212      episode=3&season=3&show=Name2

Как видите, идентификаторы строк 208 и 209 являются дубликатами друг друга, а 210 и 211 также являются дубликатами друг друга.Однако 212 существует и НЕ является дубликатом для любых других строк.

Мне удалось определить дубликаты, выполнив следующий запрос:

SELECT id, hints FROM media_items GROUP BY hints HAVING count(*) > 1;

В моей таблице 21097 строк,и вышеупомянутый запрос возвращает 2309 дубликатов.Если я выполню следующий запрос, полученный по ссылке выше, все строки, КРОМЕ ДУБЛАТОВ 2309, будут удалены, что противоположно тому, что я хочу сделать.

DELETE from media_items
WHERE rowid NOT IN (
    SELECT min(rowid) FROM media_items GROUP BY hints HAVING count(*) > 1
);

Я думаю, что это решение технически сработалопользователь, который спросил об этом, потому что ему не нужно было хранить несколько строк, которые не содержали дубликатов.

Я также пробовал следующий запрос, который имеет смысл для меня (я явно недопонимаю), но онудаляет только 1 строку за раз, и если я кропотливо запускаю ее столько раз, сколько у меня дубликатов (2309), она на самом деле идет дальше и начинает удалять недубликаты.

DELETE FROM 'media_items'
WHERE id = (
    SELECT MIN(id) FROM 'media_items' GROUP BY hints HAVING COUNT(*) > 1
); 

Возможно ли это?

Ответы [ 2 ]

0 голосов
/ 09 декабря 2018

Если вы хотите удалить все строки дубликатов, то:

DELETE FROM media_items
WHERE EXISTS (SELECT 1
              FROM media_items mi2
              WHERE mi2.hint = media_items.hint AND mi2.id <> media_items.id
             );

Если вы хотите сохранить одну из строк из дубликатов, скажем, одну с наименьшим идентификаторомЯ бы порекомендовал коррелированный подзапрос:

DELETE FROM media_items
WHERE id > (SELECT MIN(mi2.id)
            FROM media_items mi2
            WHERE mi2.hint = media_items.hint
           );

Я настоятельно советую вам не использовать NOT IN с подзапросами.Я должен работать в этом случае, потому что я сомневаюсь, что id может когда-либо быть NULL.Но одно значение NULL, возвращаемое подзапросом, приведет к удалению не строк - даже для истинных дубликатов .

Из-за этого нелогичного поведения используйте прямые сравнения или NOT EXISTS.

0 голосов
/ 09 декабря 2018

Предполагая, что вы всегда хотите сохранить наименьшее id из дубликатов:

DELETE
FROM media_items
WHERE id NOT IN (SELECT MIN(id) FROM media_items GROUP BY hints);

Вышеприведенный подзапрос находит для каждой группы подсказок (которая может быть только одной подсказкой) наименьший id для этой группы.Запрос на удаление затем избавляет от удаления минимум 10000 *, тогда как все остальные будут удалены.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...