mysql去重、多列去重

MySQL 数据去重可是 MySQL 必会技能之一。比如,在数据库中找出使用相同 email 但不同 username 的用户等应用场景。

本教程将介绍 4 种删除重复数据的方法。SELECT DISTINCT、GROUP BY 、INNER JOIN 、ROW_NUMBER() ,它们各有各的特点。

准备数据

请登录你的 MySQL 服务器,然后将以下代码贴进去执行。我们先来创建教程示例数据:

CREATE TABLE users (
    id INT PRIMARY KEY AUTO_INCREMENT,
    first_name VARCHAR(50) NOT NULL,
    last_name VARCHAR(50) NOT NULL,
    email VARCHAR(255) NOT NULL
);

INSERT INTO users (first_name,last_name,email) 
VALUES ('Chuan ','Jiang','HiJiangChuan@gmail.com'),
       ('Chuan ','Jiang','HiJiangChuan@gmail.com'),
       ('Ch. ','Jiang','HiJiangChuan@gmail.com'),
       ('Ke','Xie','xieke@sina.com'),
       ('Ke','Xie','xieke@qq.com'),
       ('Amei','Song','amei@163.com');

select * from users;


我们可以看到,示例数据中有多组不同程度的重复数据,接下来我们使用 4 种方法演示如何去重。

1. 使用 SELECT DISTINCT 命令去重

需求:查找 users 表中的数据,将记录中 first_name、 last_name、 email 这三列均重复的记录删掉,并重新整理 ID,使 ID 连续。

我们先新建一个表,然后使用 SELECT DISTINCT 去重,并把去重后的数据存进新表。

CREATE TABLE users_copy (
    id INT PRIMARY KEY AUTO_INCREMENT,
    first_name VARCHAR(50) NOT NULL,
    last_name VARCHAR(50) NOT NULL,
    email VARCHAR(255) NOT NULL
);

INSERT INTO users_copy (first_name,last_name,email) 
SELECT DISTINCT first_name,last_name,email FROM users;

我们用 select 来查看一下去重的效果:

select * from users_copy;

从返回结果看,与 ID 1 一模一样的 ID 2 被删掉,然后表格的 ID 进行了重置。

最后我们删掉 users 表,将 users_copy 改名为 users ,使用这种方法达到将原表去重的目的。

drop tables users;
alter table users_copy rename to users;
select * from users;

在这个示例中,我们删除了记录中,姓名和邮箱完全一致的重复用户信息,即删除所有列均是重复的记录。如果我们只想查某几个列是否重复应该怎么做呢?

2.使用 group by 命令去重

问题:只想查同一个姓和名,但邮箱不同(用户使用多个邮箱注册)的记录,然后删掉最有一条。

用上文的数据继续操作,我们使用 group by 去重,同样用创建中间表的方案:

CREATE TABLE users_group_by (
    id INT PRIMARY KEY AUTO_INCREMENT,
    first_name VARCHAR(50) NOT NULL,
    last_name VARCHAR(50) NOT NULL,
    email VARCHAR(255) NOT NULL
);

INSERT INTO users_group_by (first_name,last_name,email) 
SELECT first_name,last_name,ANY_VALUE(email)
FROM users
group by first_name,last_name;

我们来看一下效果:

SELECT * FROM users_group_by;


最后我们删掉 users 表,将 users_group_by 改名为 users ,使用这种方法达到将原表去重的目的。

drop tables users;
alter table users_group_by rename to users;
select * from users;

3. 使用 INNER JOIN 删除重复行

我们使用 DELETE 和 INNER JOIN 语句的组合对 MySQL 进行去重。使用这个组合时,我们的表需要有至少一个「唯一」的列(例如主键)

先来重置一下示例数据:

DROP TABLE users;
DROP TABLE users_copy;
DROP TABLE users_group_by;

CREATE TABLE users (
    id INT PRIMARY KEY AUTO_INCREMENT,
    first_name VARCHAR(50) NOT NULL,
    last_name VARCHAR(50) NOT NULL,
    email VARCHAR(255) NOT NULL
);

INSERT INTO users (first_name,last_name,email) 
VALUES ('Chuan ','Jiang','HiJiangChuan@gmail.com'),
       ('Chuan ','Jiang','HiJiangChuan@gmail.com'),
       ('Ch. ','Jiang','HiJiangChuan@gmail.com'),
       ('ke','xie','xieke@caowutech.com'),
       ('ke','xie','xieke@qq.com'),
       ('amei','song','amei@163.com');

select * from users;

需求:找出 users 表中重复 first_name 和 last_name ,并将这一行记录删掉:

DELETE t1 FROM users t1
	INNER JOIN users t2
WHERE
	t1.id < t2.id
AND t1.first_name = t2.first_name AND t1.last_name = t2.last_name;
select * from users;

注意看 t1.id < t2.id ,SQL 会删掉两组记录对比中,ID 较小的记录,即重复记录中第一组数据,把这个符号反过来,则会保留重复记录中最后一组数据。

4. 使用 ROW_NUMBER() 删除重复记录

最后,我们来说说 ROW_NUMBER() 函数,从 MySQL 8.0 开始才支持此函数。

需求:找出 users 表中重复的 last_name 和 email,并将这一行记录删掉:

DELETE FROM users
WHERE id IN (
    SELECT id
    FROM (
        SELECT 
            id, ROW_NUMBER () Over (PARTITION BY last_name,email ORDER BY id) as r 
        from users
    ) t
    WHERE r > 1
);
select * from users;


最后,我们获得了一组非常干净的 users 表。

原文链接

posted on 2022-05-20 13:31  耀扬  阅读(5394)  评论(0编辑  收藏  举报

导航