Mysql删除重复数据

一.简介

假设表结构:

CREATE TABLE `user` (

  `user_id` int(11) NOT NULL COMMENT '用户Id',

  `brand_id` int(11) NOT NULL COMMENT '品牌Id',

  `cellphone` varchar(20) DEFAULT NULL COMMENT '手机号,指定品牌下的网友唯一标识',

  `update_date` datetime DEFAULT NULL COMMENT '更新时间',

  PRIMARY KEY (`user_id`)

) ENGINE=InnoDB DEFAULT CHARSET=gbk COMMENT='用户信息表'


在该表的n条记录里,存在着些相同的记录,如何能用SQL语句,删除掉重复并保留一条呢?方法有以下两种:

1、通过中间表实现;2、在表内用sql实现;【以上两种方法,个人推荐第二种,本博客会详细分析第二种】


二.通过中间表实现

     1) 使用 create table like 复制出来一个中间表 ,然后用insert into select 把不重复的表导入到中间表中,然后再用中间表替代旧表。 具体实现如下:

  create table tmp_user like user;

  Insert into tmp_user (user_id, brand_id,cellphone,update_date) select min(`user_id`),brand_id,cellphone,update_date from user group by cellphone ;

  drop  table users ;

  alter  table  tmp_user rename user;


     2) 使用 create table select 直接复制出来一个含有数据的中间表 然后用中间表替代旧表。 具体实现如下:

  create table tmp_user(user_id, brand_id,cellphone,update_date)  select min(`user_id`),brand_id,cellphone,update_date from user group by cellphone ;

  truncate table user;

  insert into user select * from tmp_user;

  drop table tmp_user;


以上两种方法的区别就是 create table like 和 create table select 的区别。create table like 复制的表结构包含索引 而 create table select 不包含索引,没有索引对业务影响很大,这个要特别留意的。还有就是create table like 和 create table select 复制的表没有把表的权限给copy过来。要事后从新设置下。数据量大的时候应该选择 create table select ,先倾倒数据事后再为表建立索引。

至于用中间表的数据更新旧表的策略,要么用drop旧表再rename中间表。 要么清空旧表数据再导入中间表数据。数据量大的时候前面方法效率较高。

三.在表内用sql实现

1)找到要删除的数据 然后删除这些数据。

具体实现如下,

    delete user as a from user as a,(

         select min(user_id) as id_temp , cellphone from user group by cellphone having count(cellphone) > 1

     ) as b

     where a.cellphone = b.cellphone and a.user_id <> b.id_temp;

     加上 having count(name) > 1 可以避免扫描没有重复的记录,提高效率


  2)找到要保留的数据 然后用not in 来删除不再这些数据中的记录。

大家很容易就想到如下的sql语句:

     delete from user where user_id not in ( select min(user_id) from user group by cellphone ); 但是mysql删除动作不能带有本表的查询动作,意思是你删除user表的东西不能以user表的信息为条件,所以这个语句会报错,执行不了。只要通过创建临时表作为查询条件。

具体实现如下:

delete from user where user_id not in ( select * from ( select min(user_id) from user group by cellphone ) as temp );

ps: count(x)会排除字段x为空的情况,加入cellphone中存在null的值,则使用group by having的时候不要用count(cellphone),而是使用count( user_id )


四.找出表中的重复记录(各种条件)【推荐】

1、查找表中多余的重复记录,重复记录是根据单个字段(cellphone)来判断

SELECT cellphone,COUNT(*) FROM `user` GROUP BY cellphone HAVING COUNT(cellphone)>1


2、查找表中多余的重复记录,重复记录是根据多个字段来判断

找重复的手机号:

SELECT brand_id,cellphone,COUNT(*) FROM `um_user` GROUP BY brand_id,cellphone HAVING COUNT(*)>1


找所有重复数据,按更新时间顺序排序:

SELECT u1.user_id,u1.brand_id,u1.cellphone,u1.update_date

FROM `user` u1,

(

  SELECT `brand_id`,`cellphone` FROM `user` GROUP BY `brand_id`,`cellphone` HAVING COUNT(1) > 1

) AS u2

WHERE u1.`brand_id` = u2.`brand_id`

  AND u1.`cellphone` = u2.`cellphone` 

  ORDER BY u1.brand_id,u1.cellphone,u1.update_date ASC 


剔除找到的结果集的最新一条记录(更新时间不一样)以后的 需要删除的 所有数据:

SELECT u1.user_id,u1.brand_id,u1.cellphone,u1.update_date

FROM `user` u1,

(

  SELECT DISTINCT MAX(update_date) AS update_date,`brand_id`,`cellphone` FROM `user` GROUP BY `brand_id`,`cellphone` HAVING COUNT(1) > 1

) AS u2

WHERE u1.`brand_id` = u2.`brand_id`

  AND u1.`cellphone` = u2.`cellphone` 

  AND u1.update_date <> u2.update_date

  ORDER BY u1.brand_id,u1.cellphone,u1.update_date ASC 


剔除找到的结果集的最新一条记录(更新时间一样)以后的 需要删除的 所有数据:

SELECT u1.user_id,u1.brand_id,u1.cellphone,u1.update_date

FROM `user` u1,

(

  SELECT DISTINCT MAX(user_id) AS user_id,`brand_id`,`cellphone` FROM `user` GROUP BY `brand_id`,`cellphone` HAVING COUNT(1) > 1

) AS u2

WHERE u1.`brand_id` = u2.`brand_id`

  AND u1.`cellphone` = u2.`cellphone` 

  AND u1.user_id <> u2.user_id

  ORDER BY u1.brand_id,u1.cellphone,u1.update_date ASC 



你可能感兴趣的:(Mysql删除重复数据)