数据库中单表根据某几个字段去重【我】
java类:
package duplicate.removal; import java.util.List; import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class DuplicateRemoval { private final static Logger logger = LoggerFactory.getLogger(DuplicateRemoval.class); public static void main(String[] args) { //查询重复数据 List<Map> repeatedDataInfo = this.selectList("xxxx.getRepeatedDataInfo"); logger.info("查询是否存在重复数据,查询结果:{}",repeatedDataInfo); if(repeatedDataInfo!=null && repeatedDataInfo.size()>0) { //根据查询到的重复数据条件组 循环删除重复记录 for (Map map : repeatedDataInfo) { //删除重复记录只保留一个 logger.info("查询客户关系存在重复数据,执行循环删除,当前删除条件:{}",map); //先查询一下重复数据,打印到日志里以备后查,这一步可以没有 List<Map> dataList = this.selectList("xxxx.getRepeatedDataList",map); logger.info("查询客户关系存在重复数据,执行循环删除,当前即将删除数据集合:{}",dataList); //真的执行删除(这里是逻辑删除,只改状态字段)操作 this.update("xxxx.updateRepeatedData", map); } } } }
Mapper文件:
<!-- 获取重复记录字段信息列表 去重条件:表中的 P_ID、CUST_ID、REGION_CODE 三个字段一样的数据多余2条即认为是重复数据, where后面可以增加一些其他附件查询条件, 返回结果: MAX(ID) ID 是取出每一组重复条件数据中重复数据ID最大的一个,作为后面的保留数据 其他三项为重复数据的三个字段值 --> <select id="getRepeatedDataInfo" resultType="java.util.Map"> SELECT MAX(ID) ID, u.P_ID P_ID, u.CUST_ID CUST_ID, u.region_code REGION_CODE, COUNT(1) cnt FROM CUST_RECORD u WHERE status_cd = '1000' AND SERIAL_NUM LIKE 'PL%' GROUP BY u.P_ID, u.CUST_ID, u.region_code HAVING cnt > 1 LIMIT 99999; </select> <!-- 获取将要删除的重复记录详情集合 根据第一步查询出的重复数据的条件组,查询每一组重复数据,其中ID != #{ID}过滤掉要保留的那条数据 --> <select id="getRepeatedDataList" parameterType="java.util.Map" resultType="java.util.Map"> SELECT * FROM CUST_RECORD WHERE status_cd = '1000' AND P_ID = #{P_ID} AND CUST_ID = #{CUST_ID} AND region_code = #{REGION_CODE} AND ID != #{ID} AND SERIAL_NUM LIKE 'PL%'; </select> <!-- 删除(更新状态为失效)重复记录只保留一个 根据第一步查询出的重复数据的条件组,删除每一组重复数据,其中ID != #{ID}过滤掉要保留的那条数据 --> <update id="updateRepeatedData" parameterType="java.util.Map"> update CUST_RECORD set STATUS_CD = '1100',STATUS_DATE = NOW(),UPDATE_DATE=NOW() WHERE status_cd = '1000' AND P_ID = #{P_ID} AND CUST_ID = #{CUST_ID} AND region_code = #{REGION_CODE} AND ID != #{ID} AND SERIAL_NUM LIKE 'PL%'; </update>
注意:
此方法有一个问题就是如果当前表中数据量比较大时,第一个分组查询可能会报数据库内存溢出,或者查询速度特别慢,所以如果要分组的数据量很大这种方式尽量不要用。
最好的去重方式就是在插入前先查询判断,如果数据库中不存在才插入。