SQLite:删除重复项,但保留一个和非重复字段

时间:2018-12-09 14:53:03

标签: sql sqlite

我遇到了一个问题,即以某种方式重复行已进入数据库,其中某列重复。我进行了一些研究,发现像this one这样的帖子可以正常工作,只是它删除了除重复项之一以外的所有行。

我的表结构如下:

  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

如您所见,行ID 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 :(得分:1)

假设您始终要保留重复项中最小的id

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

上面的子查询为每组提示(可能只是一个提示)找到了该组的最小id。然后,删除查询将保留最小的id,而其他所有查询将被删除。

答案 1 :(得分:0)

如果您要删除重复的所有行,则:

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

如果您想保留重复项中的某一行,请说 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值将导致删除 no 行-即使对于真正的重复项也是如此。

由于这种违反直觉的行为,请使用直接比较或NOT EXISTS