|| 写在前面
要说今天刷题收获的话:
- 1 就是不要提前去看答案,顺着自己的思路多摸索摸索,逻辑链会一点点完善最后通畅
退一步说,如果实在不会后看了没人的思路,就千万不要看别人的代码!再退一步说,如果看了别人的代码,就千万别只看一半!要看完! - 2 还有一些 常用操作的补充:
》处理表:辅助表,内外联结和自联结
》基操:删除自联结的表时delete后需要加上一个副表名,ifnull()函数,is null 条件判断,涉及去重计数时count()里面就不能随便扔个*号了 (注意:没有count(distinct *)写法)
题一:编写一个 SQL 查询,满足条件:无论 person 是否有地址信息,都需要基于两表提供 person
的以下信息:
FirstName, LastName, City, State
解题思路:使用左外联结(Person作为左表) > > > 用时:60ms 内存:0B
select FirstName, LastName,City,State
from person left join address on Person.PersonId = Address.PersonId;
题二:查询第二大的数
解题思路一:返回去掉最大值后的表的最大值 > > > 用时:143ms 内存:0
解题思路二:limit语句挑出第二大值,isfull处理null情况 > > > 用时:109ms 内存:0
select max(Salary) as SecondHighestSalary from Employee
where Salary != (select max(Salary) as SecondHighestSalary from Employee);
select ifnull(
(select distinct Salary from Employee order by Salary desc limit 1,1), null) as SecondHighestSalary;
题三:求第N高的薪水
解题思路一:同上思路二 > > > 用时:148ms 内存:0
CREATE FUNCTION getNthHighestSalary(N INT) RETURNS INT
BEGIN
if N<0 then
RETURN (select min(Salary) from Employee);
else
set N = N-1;
RETURN (
# Write your MySQL query statement below.
select ifnull((select distinct Salary from Employee order by Salary desc limit N,1),null) as NthHighestSalay
);
end if;
END
题四:编写一个 SQL 查询来实现分数排名。如果两个分数相同,则两个分数排名(Rank)相同。
请注意,平分后的下一个名次应该是下一个连续的整数值。换句话说,名次之间不应该有“间隔”。
题五:Employee 表包含所有员工,他们的经理也属于员工。每个员工都有一个 Id,此外还有一列对应
员工的经理的 Id。
解题思路一:使用内连接把经理扔到右边去,再通过自联结筛选满足条件的员工 用时:263ms 内存:0B
select a.name as employee
from employee a inner join employee b
on a.ManagerId=b.Id and a.salary > b.salary;
题六:编写一个 SQL 查询,查找 Person 表中所有重复的电子邮箱。
解题思路一:自联结查询 > > > 用时:556 ms (极慢)内存:0B
解题思路二:内联结+自联结 > > > 用时:193 ms 内存:0B
解题思路三:创建一个辅助表 > > > 用时:150ms 内存:0B
解题思路四:分组后having筛选
select distinct email from person a where email in (select email from person b where a.id != b.id);
select distinct a.email from person a inner join person b on a.email = b.email and a.id != b.id;
select email from (select email, count(*) as num from person group by email)as a where num > 1;
select email
from person
group by email
having count(*) > 1;
题七:某网站包含两个表,Customers 表和 Orders 表。编写一个 SQL 查询,找出所有从不订购任何东西的客户
解题思路一:稀奇古怪顺手就用了两个表自联结形成辅助表 > > > 用时:233ms 内存:0B
解题思路二:用 is null 逻辑判断符 (注意不是 =null) > > > 用时:260ms (较慢)内存:0B
select name as customers from customers as c where c.id not in (select new.Id from (select a.id as id from customers a right join orders b on a.id= b.customerid) as new);
select name as customers from customers a left join orders b on a.id = b.customerid where customerid is null;
题八:编写一个 SQL 查询,来删除 Person 表中所有重复的电子邮箱,重复的邮箱里只保留 Id 最小 的那个。
解题思路一:按部就班,只查询出不重复的邮箱 或 重复了但id最小的邮箱
解题思路二:用delete 自联结删除其中一个表中的行就行
select * from person a
where email not in (select a.email from person a group by email having count(*) > 1)
or
(email in (select a.email from person a group by email having count(*) > 1)
and a.id < any(select b.id from person b where a.email = b.email) );
DELETE P1
FROM Person P1, Person P2
WHERE P1.Email = P2.Email
AND P1.Id > P2.Id
题九:给定一个 Weather 表,编写一个 SQL 查询,来查找与之前(昨天的)日期相比温度更高的所有日期的 Id
解题思路一:日期比较datediff()函数 用时:286ms(快) 内存:0
select a.id from weather as a, weather as b where a.temperature>b.temperature
and
DATEDIFF(a.RecordDate, b.RecordDate) = 1;
题十:有一个courses 表 ,有: student (学生) 和 class (课程)。
请列出所有超过或等于5名学生的课。
解题思路一:注意学生重复选择一门课的情况,在去重计数时 不能使用count(distinct *)
--错误写法!
select class from courses group by class having count(*) >= 5;
--right
select class from courses group by class having count(distinct student) >= 5;