LeetCode182:Duplicate Emails
Write a SQL query to find all duplicate emails in a table named Person
.
+----+---------+
| Id | Email |
+----+---------+
| 1 | a@b.com |
| 2 | c@d.com |
| 3 | a@b.com |
+----+---------+
For example, your query should return the following for the above table:
+---------+ | Email | +---------+ | a@b.com | +---------+
一道简单的SQL题目,得到重复的Email数据。
起先的想法很天真,
1、借用group by去除重复的Email数据:
SELECT Id FROM Person GROUP BY Email;
2、然后通过得到的Id过滤掉原表的数据:
SELECT DISTINCT Email FROM Person WHERE Id NOT IN (SELECT Id FROM Person GROUP BY Email);
点提交,然后:Time Limit Exceeded......
事实上第一句 SELECT Id FROM Person GROUP BY Email 的语法就是错误的,只是MYSQL支持了这一种反逻辑的写法。
GROUP BY
在W3里给出的含义是:
GROUP BY 语句用于结合聚集函数,根据一个或多个列对结果集进行分组。
通常用法是:
SELECT Name,COUNT(Salary) FROM Employee GROUP BY Name;
而GROUP BY在MYSQL中的逻辑是:
SELECT的返回字段,如果不在GROUP BY中,也不是聚集函数,那么字段的取值是从匹配的记录中随机取的;
在做表关联统计的时候,可以简化GROUP BY后面的字段,只需要GROUP BY parent.Id 就可以了,而不用把 parent 的所有字段都列出来。
举个例子:
SELECT Parent.*, COUNT(Item.Id) AS Item_count FROM Parent LEFT JOIN Item ON Parent.Id = Item.Parent_Id GROUP BY Parent.Id;
这种写法确实可以让SQL书写简化,其他的标准数据库中如果要实现同样的功能就必须用嵌套来实现:内部SQL用GROUP BY来返回Id字段,然后用返回的Id字段去关联表实现其他详细字段的输出。
但还是不推荐MySQL的这种使用方法,虽然方便,但违反了SQL约定的逻辑:有GROUP BY的输出字段要么是聚集函数,要么是在GROUP BY中。
最后给出此题的正确解法,采用INNER JOIN,过滤条件是两条数据的Email值相等但Id不相等。
SELECT DISTINCT p.Email FROM Person p INNER JOIN Person q ON p.Id != q.Id AND p.Email = q.Email;
或者
SELECT DISTINCT p.Email FROM Person p,Person q WHERE p.Id != q.Id AND p.Email = q.Email;