MYSQL 删除重复数据只保留一条

274 阅读3分钟

需求

有一个表一开始没有做唯一索引导致数据有重复的数据,为了查询时候代码不做去重打算在表创建唯一索引,但是数据库已经有重复的数据了,需要把重复的数据大于2两条的全部删除

CREATE TABLE `hub_user_group` (
  `id` bigint(20) NOT NULL,
  `uid` bigint(20) NOT NULL COMMENT '用户id',
  `group_type` int(11) NOT NULL DEFAULT '0' COMMENT '分组类型 1=黑名单 2=白名单 3=支付-白名单 ',
  `remark` varchar(255) DEFAULT NULL COMMENT '备注',
  `create_user` varchar(255) NOT NULL COMMENT '创建人',
  `create_time` datetime NOT NULL COMMENT '创建时间',
  `update_user` varchar(255) NOT NULL COMMENT '修改人',
  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
  `delete_flag` tinyint(4) NOT NULL DEFAULT '0' COMMENT '是否删除',
  PRIMARY KEY (`id`),
  KEY `idx_uid` (`uid`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户分组';

实现

DELETE FROM hub_user_group
WHERE id IN (
    SELECT id FROM (
        SELECT T1.id
        FROM hub_user_group T1
        JOIN hub_user_group T2
        ON T1.uid = T2.uid
        AND T1.group_type = T2.group_type
        AND T1.id > T2.id
    ) AS subquery
);

解释

这条 SQL 语句的目的是删除 hub_user_group 表中重复的记录,保留每组 uidgroup_typeid 最小的记录。以下是对这条语句的详细解释:

语句结构

DELETE FROM hub_user_group
WHERE id IN (
    SELECT id FROM (
        SELECT T1.id
        FROM hub_user_group T1
        JOIN hub_user_group T2
        ON T1.uid = T2.uid
        AND T1.group_type = T2.group_type
        AND T1.id > T2.id
    ) AS subquery
);

分步解释

  1. 外层 DELETE 语句

    DELETE FROM hub_user_group
    WHERE id IN (
        -- Subquery here
    );
    

    这部分是删除 hub_user_group 表中满足条件的记录。具体条件由内层子查询决定。

  2. 内层子查询

    SELECT id FROM (
        -- Inner subquery here
    ) AS subquery
    

    这个子查询从 hub_user_group 表中选择需要删除的记录的 id。为了避免 MySQL 的限制(即不能在 DELETE 语句中直接引用正在修改的表),这里使用了双重子查询。

  3. 最内层子查询

    SELECT T1.id
    FROM hub_user_group T1
    JOIN hub_user_group T2
    ON T1.uid = T2.uid
    AND T1.group_type = T2.group_type
    AND T1.id > T2.id
    

    这个子查询的作用是找到所有需要删除的记录的 id。具体步骤如下:

    • 表别名:给 hub_user_group 表起别名 T1T2
    • 条件 JOIN:将 T1T2 表进行连接,条件是 T1.uid = T2.uidT1.group_type = T2.group_type。这意味着我们在比较具有相同 uidgroup_type 的记录。
    • 过滤条件T1.id > T2.id。这意味着我们只选择那些 T1id 大于 T2id 的记录。换句话说,对于每组具有相同 uidgroup_type 的记录,我们只选择那些 id 较大的记录。

    这部分子查询的结果是所有需要删除的记录的 id

  4. 删除操作

    外层 DELETE 语句使用内层子查询的结果作为条件,删除所有 id 在这些结果中的记录。

示例

假设你的表 hub_user_group 有以下数据:

id | uid | group_type | data
---|-----|------------|------
1  | 1   | A          | ...
2  | 1   | A          | ...
3  | 2   | B          | ...
4  | 2   | B          | ...
5  | 2   | B          | ...

执行上述 DELETE 语句后,表中的数据将变为:

id | uid | group_type | data
---|-----|------------|------
1  | 1   | A          | ...
3  | 2   | B          | ...

所有具有相同 uidgroup_typeid 较大的记录都被删除,只保留每组中 id 最小的记录。

希望这个解释能帮你更好地理解这条 SQL 语句的作用。如果你有任何其他问题或需要进一步的帮助,请随时告诉我。