MySQL查找重复行:三个查询结果差异及疑问解析
MySQL重复行查询结果差异解析
表结构
| Field | Type | NULL | Key | Extra | | id | int(11) | NO | PRI | auto_increment | | name | varchar(50) | YES | | | | membership | enum('Silver','Gold','Diamond') | YES | | | | interest | set('Movie','Music','Concert') | YES | | |
现有数据
+----+--------+------------+---------------+ | id | name | membership | interest | +----+--------+------------+---------------+ | 1 | Sourav | Silver | Movie,Concert | | 2 | Yash | Diamond | Music | | 3 | Yash | Diamond | Music | | 4 | Yash | Diamond | Music | | 5 | Yash | Diamond | Music | | 6 | Yash | Diamond | Music | | 7 | Yash | Diamond | Music | | 8 | Yash | Diamond | Music | | 9 | Yash | Diamond | Music | | 10 | Yash | Diamond | Music | | 11 | Yash | Diamond | Music | | 12 | Yash | Diamond | Music | | 13 | Yash | Diamond | Music | | 14 | Yash | Diamond | Music | | 15 | Sneha | Silver | Concert | +----+--------+------------+---------------+ 15 rows in set (0.001 sec)
三个查询及结果
查询1:正确筛选重复行
SELECT id, name, membership, interest, count(*) FROM clients GROUP BY name, membership, interest HAVING count(*) > 1;
结果:
+----+------+------------+----------+----------+ | id | name | membership | interest | count(*) | +----+------+------------+----------+----------+ | 2 | Yash | Diamond | Music | 13 | +----+------+------------+----------+----------+
查询2:无GROUP BY的HAVING查询
SELECT name, membership, interest, count(*) FROM clients HAVING count(*) > 1;
结果:
+--------+------------+---------------+----------+ | name | membership | interest | count(*) | +--------+------------+---------------+----------+ | Sourav | Silver | Movie,Concert | 15 | +--------+------------+---------------+----------+
查询3:仅GROUP BY的查询
SELECT id, name, membership, interest, count(*) FROM clients GROUP BY name, membership, interest;
结果:
+----+--------+------------+---------------+----------+ | id | name | membership | interest | count(*) | +----+--------+------------+---------------+----------+ | 15 | Sneha | Silver | Concert | 1 | | 1 | Sourav | Silver | Movie,Concert | 1 | | 2 | Yash | Diamond | Music | 13 | +----+--------+------------+---------------+----------+
疑问解析
1. 三个查询结果差异及HAVING的作用
- 查询1:
GROUP BY name, membership, interest会把这三个字段值完全相同的行归为一组,每组统计行数count(*);HAVING count(*) > 1只保留行数大于1的组(即真正的重复组),所以仅返回Yash的那组数据。 - 查询2:未写
GROUP BY时,MySQL会把整个表当成一个组,count(*)统计全表15行数据,HAVING count(*) >1条件满足,因此返回这个唯一的组;但name, membership, interest会取表中第一行的对应值(Sourav那行),这是MySQL的特殊行为(标准SQL不允许这种写法,因为非聚合字段没有明确分组依据)。 - 查询3:和查询1一样做了分组,但没有
HAVING过滤,所以返回所有分组,不管行数多少,自然结果和前两个查询不同。
HAVING的核心作用是过滤分组后的结果,它和WHERE的区别是:WHERE过滤原始行,HAVING过滤分组后的组,只有配合GROUP BY使用才符合常规业务逻辑(无GROUP BY时仅过滤整个表这个大组)。
2. 第三个查询为何返回唯一条目
GROUP BY name, membership, interest本身会把这三个字段值相同的行合并成一个组,每个组只返回一条结果(组内非聚合字段如id会取组内任意一行的值,这里是组内最早的id),所以看起来像是“去重”后的唯一条目,本质是分组聚合的结果,而非专门的去重操作,但效果类似。
3. Sneha的条目为何排在顶部
MySQL在未指定ORDER BY的情况下,返回结果的顺序是不确定的,取决于存储引擎的物理存储顺序、分组执行计划等。这里Sneha排在前面,只是分组后MySQL返回组的顺序刚好如此,若重新插入数据或优化表,顺序可能改变。如果需要固定顺序,必须显式添加ORDER BY子句。
内容的提问来源于stack exchange,提问作者Yashasvi Haldiya
相关产品推荐
相关产品推荐

