mysql 过滤多列重复的值(保留其中一条),对单列或者多列重复的值去重

建立测试数据表

CREATE TABLE `test` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `account` varchar(255) DEFAULT NULL,
  `password` varchar(255) DEFAULT NULL,
  `deviceId` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8mb4;

INSERT INTO `test`.`test` (`id`, `account`, `password`, `deviceId`) VALUES (10, 'A', '123456', 'A111');
INSERT INTO `test`.`test` (`id`, `account`, `password`, `deviceId`) VALUES (20, 'B', '1234562', 'A222');
INSERT INTO `test`.`test` (`id`, `account`, `password`, `deviceId`) VALUES (30, 'C', '123456', 'A333');
INSERT INTO `test`.`test` (`id`, `account`, `password`, `deviceId`) VALUES (40, 'D', '1234563', 'A444');
INSERT INTO `test`.`test` (`id`, `account`, `password`, `deviceId`) VALUES (50, 'E', '1234561', 'A111');
INSERT INTO `test`.`test` (`id`, `account`, `password`, `deviceId`) VALUES (60, 'C', '1234561', 'A333');
INSERT INTO `test`.`test` (`id`, `account`, `password`, `deviceId`) VALUES (70, 'C', '1234564', 'A333');
INSERT INTO `test`.`test` (`id`, `account`, `password`, `deviceId`) VALUES (80, 'D', '1234565', 'A444');

根据单列去重

-- 找到哪些是重复的行
-- 赛选需要留下的行
-- 从重复的行去除留下的行,得到需要排除的行
SELECT
	* 
FROM
	test 
WHERE
	id NOT IN (
	SELECT
		id 
	FROM
		test 
	WHERE
		account IN ( SELECT account FROM test GROUP BY account HAVING count( account ) > 1 ) 
		AND id NOT IN ( SELECT max( id ) FROM test GROUP BY account HAVING count( account ) > 1 ) 
	)

根据多列去重

-- group by 之后使用的聚合函数都是统计组内的信息,
-- only_full_groupby模式要明确分组之后select的值应该取哪一个,如果取的字段无法适用于任何聚合函数的话,可以用any_value 但是any_value到底是取得哪一个呢,常用的场景是先排序再分组取第一个
-- 需要子查询或者join,根据查询的重复字段去原始记录表匹配
SELECT
	* 
FROM
	test 
WHERE
	id NOT IN (
	SELECT
		id 
	FROM
		test 
	join  ( SELECT account,deviceId FROM test GROUP BY account, deviceId HAVING count( account ) > 1 and count(deviceId) > 1 ) as ref 
	on ref.account = test.account and ref.deviceId = test.deviceId
		AND id NOT IN ( SELECT min(id) FROM test GROUP BY account, deviceId HAVING count( account ) > 1 and count(deviceId) > 1 ) 
	)

在查找所有的重复列的时候,可以用子查询去匹配也可以用join。看哪个用的熟练了。

简介版

SELECT
	* 
FROM
	test 
WHERE
	id  IN (SELECT min(id) AS id
      FROM test
      GROUP BY account, deviceId)

参考

https://blog.youkuaiyun.com/qq_35387940/article/details/108074927

<think>好的,我现在需要回答用户关于SQL的问题。用户想要知道如何用SQL语句重复记录,并且给出示例,特别是删除重复行并保留唯一的情况。 首先,我需要回忆一下SQL中的常用方法。记得DISTINCT关键字是用来除查询结果中的重复行的,比如SELECT DISTINCT column FROM table,但DISTINCT只能用于查询,不能直接删除表中的重复数据。所以如果用户想删除表中的重复行,可能需要用其他方法。 接下来,用户提到删除重复行并保留唯一。这时候可能需要使用DELETE语句结合子查询或者窗口函数。例如,使用ROW_NUMBER()来为每个分组内的记录编号,然后删除行号大于1的记录。或者使用EXISTS子句来检查是否存在重复记录并删除。 然后,我需要参考用户提供的引用内容。引用[1]和[2]提到了DISTINCT的用法,适用于查询。引用[3]展示了一个删除两个表中相同记录的示例,但可能不适用于同一表内的。引用[4]提到了使用ROW_NUMBER()和PARTITION BY来保留每组的第一条记录,这可能适用于删除重复保留唯一的场景。 现在需要把这些信息整合起来,提供几种不同的方法。首先介绍DISTINCT用于查询,然后说明如何删除表中的重复数据,可能包括使用临时表、使用ROW_NUMBER()窗口函数分区排序后删除,或者使用GROUP BY保留最小/最大的ID等方法。 需要注意语法正确,比如窗口函数的使用,DELETE语句的正确写法。同时,要给出具体的示例,比如使用CTE(公用表表达式)来帮助删除操作,或者子查询中的PARTITION BY。 还要考虑不同数据库系统的差异,比如MySQL、SQL Server、PostgreSQL在语法上的细微差别,但用户可能希望看到通用的解决方案,所以可能需要指出某些语法是特定于某些数据库的,比如使用ROWNUM可能是Oracle的语法。 最后,生成相关问题,例如如何选择不同的方法,如何优化性能,以及不同方法的适用场景。确保问题与用户的问题相关,并且能够引导用户进一步了解相关知识。</think>### SQL语句详解 在SQL中重复记录主要有两种场景:**查询结果**和**删除表中重复数据**。以下分别说明具体实现方法及示例: --- #### 一、查询结果 使用`DISTINCT`关键字直接过滤重复,仅保留唯一记录。 ```sql -- 单列 SELECT DISTINCT name FROM employees; -- 多列组合 SELECT DISTINCT department, job_title FROM employees; ``` `DISTINCT`作用于所有查询列的组合,仅当所有列完全相同时才会[^1][^2]。 --- #### 二、删除表中重复数据 需根据具体需求选择保留策略(如保留首行/末行),常见方法如下: 1. **使用窗口函数标记重复行** ```sql -- 示例:保留每组重复数据中的第一条记录(按插入时间排序) WITH cte AS ( SELECT *, ROW_NUMBER() OVER (PARTITION BY email ORDER BY created_at) AS rn FROM users ) DELETE FROM cte WHERE rn > 1; ``` 通过`ROW_NUMBER()`对按`email`分组的记录编号,删除编号>1的重复行[^4]。 2. **利用临时表** ```sql -- 步骤1:将数据存入临时表 CREATE TABLE tmp_table AS SELECT DISTINCT * FROM original_table; -- 步骤2:清空原表并插回数据 TRUNCATE TABLE original_table; INSERT INTO original_table SELECT * FROM tmp_table; DROP TABLE tmp_table; ``` 适用于全表,但需注意事务完整性。 3. **通过GROUP BY保留唯一键** ```sql -- 保留每组中ID最小的记录 DELETE FROM orders WHERE id NOT IN ( SELECT MIN(id) FROM orders GROUP BY customer_id, order_date ); ``` 通过子查询确定需要保留的主键,再删除其他重复记录。 --- #### 三、典型场景示例 **需求:删除用户表中重复邮箱记录,保留最新注册的记录** ```sql DELETE FROM users WHERE id NOT IN ( SELECT MAX(id) FROM users GROUP BY email ); ``` 通过`GROUP BY email`确定每组邮箱的最大ID(即最新记录),删除其他ID[^3]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值