拓扑园

  • O&M
    • Universal部署
    • PHP+VUE+Laravel相关
  • Oracle性能优化
  • Oracle项目案例
    • Oracle近期项目案例(目录)
    • Oracle实战问题解析(目录)
    • Oracle数据库名变更流程(2种方式)
    • Oracle数据库目录更换流程(使用Oracle的clone工具)
    • Oracle数据库迁移方案(目录)
    • 标准化文档系列
  • Oracle基础知识
    • LLL的Oracle培训(分类)
    • LLL的docker培训(分类)
    • 标准化文档系列--(分类)
    • Oracle核心经典分析(分类)
    • 图灵小队----(分类并包含以下文章)
    • --MySQL8.0/Oracle/Memcached/Redis等安装配置于RHEL/OL6/7/8.X系列-运行环境最优配置
    • --PG安装配置于RHEL/9X系列-运行环境最优配置
    • --自动维护任务详解-开启、关闭信息统计收集(统计信息)
    • --图灵小队—Oracle/PostgreSQL下创建一个用户测试表(自行定义数据行)
    • --图灵小队-Oracle存储过程导出表的明细_UTL_FILE(文章)
    • --图灵小队-Oracle数据库删除/卸载操作指南(文章)
    • --图灵小队-Oracle常用性能查询SQL语句(文章)
    • --图灵小队-Oracle数据库上线前检查(文章)
    • --图灵小队-Oracle常用SQL语句(文章)
    • --图灵小队—Linux/Oracle脚本/MySQL合集(持续更新)
    • --图灵小队-Oracle技巧记录(文章)
    • ADG
    • RAC
    • ASM
    • OGG
    • RMAN
    • EXPDP/IMPDP
    • 工厂数据导入导出系列
  • MySQL
    • MySQL数据库规范
    • MySQL项目案例
    • MySQL安装配置
    • MYSQL集群项目
    • MySQL常见处理
    • MySQL-Sysbench专题
    • MySQL-Percona Toolkit专题
  • Linux
    • Shell编程
    • kubernetes
    • docker
    • Linux
    • PHP
    • Nginx
    • haproxy
    • mail
    • 网站
    • 域名
    • 网址收藏
  • 数据中心
    • 新框架系统集合
    • 工作文档
    • EBS数据文件扩容
    • VMware虚拟化
    • EBS系列
    • 大数据
    • SVN
    • zabbix
    • SAP
    • 备份相关
    • FC交换机
    • SVN
  • K-Studing
    • D8-Python学习
    • Oracle/MySQl等面试题
    • LG-MySQL
    • LG-Docker/K8S
    • LG-PostgreSQL
    • LG-ORACLE_BBED
    • LG-ORACLE
    • LG-Elasticsearch(ES)+ELK
    • Oracle-19C-OCP
    • WERN_ORACLE培训
    • redis数据库
    • Nginx培训学习系列
  • 其他
    • 外研英语4年级下册-听力
    • 影视系列
    • 如何使用iTunes软件通过抓包下载旧版本的ios的app
天高任鸟飞
Oracle/MySQL数据库恢复/数据迁移/生产规范报告技术交流:TEL:18562510581(微信同号);加微信入群
  1. 首页
  2. Oracle基础知识
  3. 图灵小队
  4. 正文

mysql下删除重复数据的方法(多种)

2024年6月13日 3695点热度 1人点赞 0条评论

目录

  • 一、重删前的检查数据
    • 1、静态表适用
      • (1)查看当前数据(生产中不用看)
      • (2)获取表当前的数据总量
      • (3)查看以ID为重复值的列,共有多少组有重复值
      • (4)查看去重后有多少条
      • (5)需要删除的数据有多少条?
    • 2、动态表适用(数据量不断变化?)
  • 二、使用存储过程删除
    • 1、方式1--存储过程直接循环删除重复数据
      • (1)创建存储过程
      • (2)执行存储过程—移除重复复数据
    • 2、方式2--存储过程利用临时表方式删除重复数据(未整理完全,未通过测试)
      • (1)创建存储过程
  • 三、使用SQL语句进行删除
    • 1、使用sql语句删除--新增主键列方式
    • (此方式适用于表数据量不多,比如几百万行,但是重复数据较多,比如几十万行的)
      • (1) 第一步 新增自增主键(此步骤是为了辅助第二步)
      • (2)第二步-删除重复数据
      • (3)第三步 删除 t_id 列
      • (4)第四步-添加主键
    • 2、快速创建主键的方法(和1一样)
      • (1)添加自增列作为临时主键:
      • (2)使用临时主键删除重复记录:
      • (3)移除临时主键并添加真正的主键:
    • 注意事项:
  • 四、python脚本去重

查看重复数据数量(以id为重复列)

select id from (select id from laundry.cr01_archive group by id having count(*) > 1) as duplicates;

一、重删前的检查数据

删除前对数据表量进行统计(方便后续进行验证数据一致性),所有数据重删前都要进行检查。

1、静态表适用

(1)查看当前数据(生产中不用看)

mysql> select * from test01 order by id;
+----+-------+------------------+
| id | name | valid_card_number |
+----+-------+------------------+
| 1  | LLL01 | 111              |
| 1  | LLL01 | 111              |
| 1  | LLL01 | 111              |
| 1  | LLL01 | 111              |
| 1  | LLL01 | 111              |
| 2  | LLL02 | 111              |
| 2  | LLL02 | 111              |
| 2  | LLL02 | 111              |
| 2  | LLL02 | 111              |
| 3  | LLL03 | 111              |
| 3  | LLL03 | 111              |
| 4  | LLL04 | 111              |
| 4  | LLL04 | 111              |
| 5  | LLL05 | 111              |
| 5  | LLL05 | 111              |
| 6  | LLL06 | 111              |
| 6  | LLL06 | 111              |
| 7  | LLL07 | 111              |
+----+-------+------------------+

(2)获取表当前的数据总量

select count(*) from test01;  --18条

(3)查看以ID为重复值的列,共有多少组有重复值

select id from test01 group by id having count(*) > 1; --6组
select count(id) from (select id from test01 group by id having count(*) > 1) as duplicates;--6组

(4)查看去重后有多少条

select count(*) from (select distinct(id) from test01) as distincts; --7条

(5)需要删除的数据有多少条?

18-7=11条

2、动态表适用(数据量不断变化?)

确认数据时间点,比如确认数据的时间范围条件,确保这短时间的数据是稳定的。

测试可以通过,不间断的插入数据,作为测试条件。

写一个mysql数据库存储过程,不间断的插入数据。包括时间点

(1)先插入批量数据,比如200行,

(2)确认一个时间点,然后查询这个时间点的数据

注意:如果这个时间点又有了重复数据,怎么办?

不会的,因为我们给表创建了一个新的自增列(自增列拥有唯一性),所以不可能再出现重复数据的情况。

因为自增列最后要删除的,如果最后删除后,又有了新的重复列(比如前两列一样,第三列是自增列),删除第三列,前两列还是有重复的,那么此时再走一遍去重操作?重复数据少的情况下,其实很快,上亿的数据,也就几分钟就可以去重,但增加自增列可能需要一些时间,只能祈祷在这个时间里,不要再有除了自增列再有重复数据的情况。

需要测试,测试,测试。

 

 

二、使用存储过程删除

1、方式1--存储过程直接循环删除重复数据

缺点:此存储过程执行一次只删除每组重复行的一条数据行,如果相同的重复行有几十次,几百次,就不好用了

(1)创建存储过程

DELIMITER $$

CREATE PROCEDURE RemoveDuplicateRecords_cbbt_coin_collection()
BEGIN
    DECLARE done INT DEFAULT FALSE;
    DECLARE current_id INT;
    DECLARE cur CURSOR FOR 
        SELECT id FROM (
            SELECT id, ROW_NUMBER() OVER(PARTITION BY id ORDER BY id) AS row_num
            FROM laundry.cbbt_coin_collection
        ) AS duplicates
        WHERE row_num > 1;
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;

    OPEN cur;
    read_loop: LOOP
        FETCH cur INTO current_id;
        IF done THEN
            LEAVE read_loop;
        END IF;

        DELETE FROM laundry.cbbt_coin_collection WHERE id = current_id LIMIT 1;
    END LOOP;
    CLOSE cur;
END$$

DELIMITER ;

(2)执行存储过程—移除重复复数据

CALL RemoveDuplicateRecords();

2、方式2--存储过程利用临时表方式删除重复数据(未整理完全,未通过测试)

为了快速删除重复数据,可以编写一个存储过程来处理这个任务。存储过程将会使用循环和临时表来识别和删除重复数据。以下是一个示例存储过程的框架,你可以根据具体情况进行调整和优化:

(1)创建存储过程

DELIMITER //

CREATE PROCEDURE deleteDuplicateRows()
BEGIN
    DECLARE done INT DEFAULT FALSE;
    DECLARE id_value INT;
    DECLARE min_t_id INT;

    -- Cursor to iterate over distinct id values
    DECLARE cur CURSOR FOR 
        SELECT DISTINCT id FROM your_table;

    -- Temporary table to store min t_id for each id
    CREATE TEMPORARY TABLE IF NOT EXISTS tmp_min_t_id (
        id INT,
        min_t_id INT,
        PRIMARY KEY (id)
    );

    -- Handler for cursor
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;

    -- Open cursor and iterate over each id
    OPEN cur;
    read_loop: LOOP
        FETCH cur INTO id_value;
        IF done THEN
            LEAVE read_loop;
        END IF;

        -- Find minimum t_id for current id
        SELECT MIN(t_id) INTO min_t_id
        FROM your_table
        WHERE id = id_value;

        -- Insert into temporary table
        INSERT INTO tmp_min_t_id (id, min_t_id) VALUES (id_value, min_t_id);
    END LOOP;
    CLOSE cur;

    -- Delete duplicate rows except for the ones with min t_id
    DELETE yt
    FROM your_table yt
    JOIN tmp_min_t_id tmp ON yt.id = tmp.id AND yt.t_id <> tmp.min_t_id;

    -- Drop temporary table
    DROP TEMPORARY TABLE IF EXISTS tmp_min_t_id;
    
END //

DELIMITER ;

说明:

  1. Cursor 部分:使用游标遍历表中的每个不同的 id 值。
  2. 临时表:创建临时表 tmp_min_t_id,用于存储每个 id 对应的最小 t_id 值。
  3. 循环处理:在循环中,对每个 id 找到其最小 t_id 值,并插入临时表。
  4. 删除操作:利用临时表,删除表 your_table 中除了每个 id 对应的最小 t_id 之外的所有记录。
  5. 清理工作:删除完成后,临时表会自动删除。

使用方法:

三、使用SQL语句进行删除


1、使用sql语句删除--新增主键列方式

(此方式适用于表数据量不多,比如几百万行,但是重复数据较多,比如几十万行的)

test01删除重复数据并创建主键-SQL语句展开查看

(1) 第一步 新增自增主键(此步骤是为了辅助第二步)

运行前提是表中没有自增键,如果自增键,则无需本步,

ALTER TABLE test01 ADD COLUMN t_id INT AUTO_INCREMENT PRIMARY KEY FIRST;

(2)第二步-删除重复数据

DELETE t1
FROM test01 t1
JOIN (
    SELECT id, MIN(t_id) AS keep_id
    FROM test01
    GROUP BY id
    HAVING COUNT(*) > 1
) t2 ON t1.id = t2.id AND t1.t_id <> t2.keep_id;

 

DELETE n1 
FROM n02_archive n1  
JOIN (
    SELECT MIN(t_id) AS min_id, trans_id 
    FROM n02_archive GROUP BY trans_id
    ) n2 ON n1.t_id <> n2.min_id AND n1.trans_id = n2.trans_id;
DELETE t1
FROM test01 t1
JOIN (
    SELECT id, MIN(t_id) AS keep_id
    FROM test01
    GROUP BY id
    HAVING COUNT(*) > 1
) t2 ON t1.id = t2.id AND t1.t_id <> t2.keep_id;

(3)第三步 删除 t_id 列

ALTER TABLE test01 DROP COLUMN t_id;

(4)第四步-添加主键

ALTER TABLE test01 ADD PRIMARY KEY (trans_id);

如果你的 MySQL 表没有主键且没有任何唯一属性列,但你需要快速创建主键并保留每组重复数据中的第一条记录,可以按照以下步骤操作:

2、快速创建主键的方法(和1一样)

(1)添加自增列作为临时主键:

首先,为表添加一个新的自增列作为临时主键。标识和删除重复记录,同时为表提供一个唯一标识。

ALTER TABLE your_table ADD COLUMN temp_id INT AUTO_INCREMENT PRIMARY KEY;

上述命令会在 your_table 表中添加一个名为 temp_id 的新列,自动为每行分配唯一的整数值作为主键。

(2)使用临时主键删除重复记录:

接下来,使用临时主键来标识并删除重复记录。这里假设你的表有重复数据,但你希望保留每组重复数据中的第一条记录。

DELETE t1
FROM your_table t1
JOIN (
    SELECT MIN(temp_id) AS keep_id
    FROM your_table
    GROUP BY id
    HAVING COUNT(*) > 1
) t2 ON t1.temp_id <> t2.keep_id;

your_table 是你的表名。
temp_id 是刚刚添加的临时主键列。
查询会找到每组重复数据中的第一条记录(具有最小的 temp_id 值),并删除除了第一条记录外的所有其他记录。

(3)移除临时主键并添加真正的主键:

删除完重复记录后,你可以移除临时主键列,并添加真正的主键。如果你有其他唯一属性列,可以选择将其设置为主键;否则,可以继续使用自增列作为主键。

ALTER TABLE your_table DROP COLUMN temp_id,ADD PRIMARY KEY (auto_increment_column); -- 这里替换为真正的主键列

--auto_increment_column 是你选择作为主键的列名,可以是刚刚添加的 temp_id 或其他合适的列。

注意事项:

  • 在执行这些操作之前,请务必备份你的数据,以防止意外情况。
  • 临时主键列只是为了标识和处理重复记录,最终的主键应该是表中的一个唯一标识。
  • 确保在删除重复记录后检查数据是否符合预期,特别是每组重复数据是否只保留了第一条记录。

四、python脚本去重

import mysql.connector
# 连接数据库,此处按需更改数据库信息
mysqlConnection = mysql.connector.connect(
    host="host",
    port=000,
    user="user",
    password="password",
    database="database"
)
# 创建游标
mysqlCursor = mysqlConnection.cursor()
# 待执行的 SQL 列表
sql_queries = [
    """ delete from user_third_login where id in (select id from (select id from user_third_login group by id having count(*) > 1) as duplicates) order by id limit 1;""",
    """ delete from user_refered_friend where id in (select id from (select id from user_refered_friend group by id having count(*) > 1) as duplicates) order by id limit 1;""",
    """ delete from user_third_login_deleted where id in (select id from (select id from user_third_login_deleted group by id having count(*) > 1) as duplicates) order by id limit 1;"""
]

# 循环执行 SQL
for query in sql_queries:
    while True:
        # 执行 SQL
        mysqlCursor.execute(query)
        # 获取并打印数据库返回的结果
        deleted_rows = mysqlCursor.rowcount
        if deleted_rows == 0:
            print("This sql returns: Affected rows: 0", query.strip())
            break
        else:
            print("Deleted", deleted_rows, "duplicate entries for:", query.strip())
        # 提交事务
        mysqlConnection.commit()

# 关闭游标和数据库连接
mysqlCursor.close()
mysqlConnection.close()
本作品采用 知识共享署名 4.0 国际许可协议 进行许可
标签: 暂无
最后更新:2024年6月16日

admin

这个人很懒,什么都没留下

打赏 点赞
< 上一篇
下一篇 >

COPYRIGHT © 2022 拓扑园. ALL RIGHTS RESERVED.

Theme Kratos Made By Seaton Jiang

鲁ICP备2021020523号

鲁ICP备2021020523号