好久不见SQL

最近

目录

No.1 组合两个表

No.2 获得第二高的薪水

No.3  部门工资最高的员工

 No. 4 找到第N高的薪资

 No.5 连续出现的数

 No.6 部门工资前三高的员工

No.7 每家商店的产品价格

No.8 分数排名

No.9 181. 超过经理收入的员工

No.10 262. 行程和用户

No.11 体育馆的人流量

No.12  删除重复的电子邮箱

No.13 1179. 重新格式化部门表

 No.14 182. 查找重复的电子邮箱​

 No.15 197. 上升的温度

No.16 626. 换座位

No.17 620. 有趣的电影

No.18 627. 变更性别

No.19 183. 从不订购的客户

 No.20 511. 游戏玩法分析 I

No.21 595. 大的国家 

No.22 1873. 计算特殊奖金

 No.23 1097. 游戏玩法分析 V

 No.24 569. 员工薪水中位数

 No.25 1841. League Statistics

 No.26 571. 给定数字的频率查询中位数

No.27 618. 学生地理信息报告

 No.28  1083. 销售分析 II

 No.29 1205. 每月交易II

No.30 1501. 可以放心投资的国家

 No.311821. 寻找今年具有正收入的客户

No.32 1204. 最后一个能进入电梯的人

 No.33 1082. 销售分析 I 

No.34 1098. 小众书籍

 NO.35 1270. 向公司CEO汇报工作的所有人

 No.36 597. 好友申请 I:总体通过率

 No.39  1715. 苹果和橘子的个数

No.40 1809. 没有广告的剧集

NO.42  603. 连续空余座位

No.43 1112. 每位学生的最高成绩

 No.44 1308. 不同性别每日分数总计

 No.45 570. 至少有5名直接下属的经理

No.46 580. 统计各专业学生人数 

 No.47 1407. 排名靠前的旅行者

No.48  1795. 每个产品在不同商店的价格


把很久不用的SQL拿出来温习一下,主要思路是以练代学,在练习中回忆以前学习的知识点。

学习内容来自于CSDN博主“报告,今天也有好好学习”两篇SQL的基础练习: 如何快速掌握MYSQL?附LeetCode上出现频率最高的50道数据库题目详解_老吴的博客-CSDN博客

 如何快速掌握MYSQL?附LeetCode上出现频率最高的50道数据库题目详解_老吴的博客-CSDN博客

如何快速掌握MYSQL?附牛客网所有SQL题目详解_老吴的博客-CSDN博客

开始了哦


No.1 组合两个表

select FirstName,LastName,City,State
from Person
left join Address
on Person.PersonId=Address.PersonId

LEFT JOIN 关键字从左表(table1)返回所有的行,即使右表(table2)中没有匹配。如果右表中没有匹配,则结果为 NULL。 

No.2 获得第二高的薪水

select ifNull ((
    select distinct Salary 
    from Employee 
    order by Salary desc 
    limit 1,1),Null) as SecondhighestSalary

ifNull(a,b): 如果a不等于Null,则返回a,否则返回b。是 if(X=Null,a,b)的简写

distinct:去重

limit:用于返回前几条或者中间某几行数据,(limit m,n) , m指从m+1条记录行开始检索,n代表取出n条数据

No.3  部门工资最高的员工

# 聚合函数与group by一起使用,会返回每组的聚合结果
# 聚合函数与group by直接使用的时候会出现问题,所以思路是先筛选出每组中最高的工资,再匹配数据
select b.Name Department, a.Name Employee, Salary 
from Employee a, Department b
where a.DepartmentId=b.Id and
(a.DepartmentId,Salary) in ( 
    select DepartmentId, max(Salary)
    from Employee
    group by DepartmentId )

 No. 4 找到第N高的薪资

#主要考察limit的使用
CREATE FUNCTION getNthHighestSalary(N INT) RETURNS INT
BEGIN
  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)
  );
END

 No.5 连续出现的数

# 注意连续出现至少3次的数字
select distinct a.num as ConsecutiveNums
from Logs as a, Logs as b, logs as c 
where a.num=b.num and b.num=c.num and a.id=b.id-1 and b.id=c.id-1

 No.6 部门工资前三高的员工

# 学习使用窗口函数,发现解这种排序问题使用窗口函数是很好用的
# 利用窗口函数先分组排序,再进行选取,很简单的可以解决这类问题
Select d.Name Department, ranking.Name Employee, ranking.Salary
from (
    select *, 
    dense_rank() over (partition by DepartmentId order by Salary desc ) as rk 
    from Employee) as ranking 
join Department d on ranking.DepartmentId=d.Id
where rk<4

推荐一篇讲窗口函数挺好的文章: 通俗易懂的学会:SQL窗口函数 - 知乎

No.7 每家商店的产品价格

# 注意要使用聚合函数对if的结果进行聚合,将多个结果聚合成一行
select product_id,
       sum(if(store='store1',price,null)) store1
       sum(if(store='store2',price,null)) store2
       sum(if(store='store2',price,null)) store3
from Products
group by product_id

No.8 分数排名

# 窗口函数yyds
select Score,
       dense_rank() over (order by Score desc) as 'Rank'
from Scores 

No.9 181. 超过经理收入的员工

# 
select a.Name as Employee
from Employee a 
left join Employee b on a.ManagerId=b.Id
where a.salary>b.salary 

No.10 262. 行程和用户

#join
select t.Request_at Day, Round(sum(If((Status='cancelled_by_driver' or Status='cancelled_by_client'),1,0))/count(t.Id),2) 'Cancellation Rate'
from Trips t
join Users u on t.Client_Id=u.Users_Id
join Users w on t.Driver_Id=w.Users_Id
where u.Banned!='Yes' and w.Banned!='Yes'
group by t.Request_at

No.11 体育馆的人流量

select distinct(s1.id) id, s1.visit_date, s1.people
from Stadium s1, Stadium s2, Stadium s3 
where s1.people>=100 and s2.people>=100 and s3.people>=100 
and ((s1.id=s2.id-1 and s2.id=s3.id-1) or (s1.id=s2.id+1 and s1.id=s3.id-1 ) or (s1.id=s2.id+1 and s1.id=s3.id+2))
order by s1.id

No.12  删除重复的电子邮箱

# 窗口函数还能这么使用
delete 
from Person 
where Id in (select id from (select id , row_number() over (partition by Email order by Id ) ranking from Person ) as a where ranking>1 )

No.13 1179. 重新格式化部门表

# case when 和 if 都可以使用
# 要使用聚合函数
select id, 
sum(case when month='Jan' then revenue else null end ) Jan_Revenue,
sum(case when month='Feb' then revenue else null end ) Feb_Revenue,
sum(case when month='Mar' then revenue else null end ) Mar_Revenue,
sum(case when month='Apr' then revenue else null end ) Apr_Revenue,
sum(case when month='May' then revenue else null end ) May_Revenue,
sum(case when month='Jun' then revenue else null end ) Jun_Revenue,
sum(case when month='Jul' then revenue else null end ) Jul_Revenue,
sum(case when month='Aug' then revenue else null end ) Aug_Revenue,
sum(case when month='Sep' then revenue else null end ) Sep_Revenue,
sum(case when month='Oct' then revenue else null end ) Oct_Revenue,
sum(case when month='Nov' then revenue else null end ) Nov_Revenue,
sum(case when month='Dec' then revenue else null end ) Dec_Revenue
from Department 
group by id

 No.14 182. 查找重复的电子邮箱

select distinct Email
from (
select Email, row_number() over (partition by Email) rk
from Person ) a
where rk>1

##

select Email
from Person
group by Email 
having count(Id)>1

 No.15 197. 上升的温度

select distinct w2.id
from Weather w1, Weather w2
where w1.recordDate=w2.recordDate-1 and w1.Temperature<w2.Temperature

##直接使用上述代码,逻辑上没有错,但是因为时间格式转换问题,测试用例有一个无法通过
#使用DATEDIFF就可以很好解决这个问题

select distinct w2.id
from Weather w1, Weather w2
where DATEDIFF (w1.recordDate,w2.recordDate)=-1 and w1.Temperature<w2.Temperature

No.16 626. 换座位

#我的方法是换名字,解析中更简单的思路是换ID
select id, if(
(s1.id =(select max(id) from seat) and mod(id,2)=1),student,
  if (
    mod(id,2)=1,
    (select student from seat s2 where s1.id=(s2.id-1) ),
    (select student from seat s3 where s1.id=(s3.id+1)))
) as student
from seat s1

No.17 620. 有趣的电影

select id,movie,description, rating
from cinema 
where id%2!=0 and description!='boring'
order by rating desc

No.18 627. 变更性别

update Salary 
set sex=if (sex='m','f','m')

No.19 183. 从不订购的客户

select Name as Customers
from Customers
where id not in (select CustomerId from Orders)

 No.20 511. 游戏玩法分析 I

select player_id, min(event_date) as first_login
from Activity
group by player_id

No.21 595. 大的国家 

select name,population,area
from World
where area>=3000000 or population>=25000000

No.22 1873. 计算特殊奖金

select employee_id, if(employee_id%2=0 or LEFT(name,1)='m',0,salary)as bonus
from Employee

 No.23 1097. 游戏玩法分析 V

#筛选出哪些日期有用户安装了游戏很重要

select m as install_dt, count(distinct player_id) as installs, round(sum(if(datediff(event_date,m)=1),1,0)/count(distinct player_id)) as Day1_retention
from 
(select player_id, event_date, min(event_date) over (partition by player_id) as m
from Activity) f
group by m 

 No.24 569. 员工薪水中位数

 

#米有leecode会员,没想到不使用任何内置函数的情况下解决的办法
# 窗口函数解决起来还是很简单的
select id, company salary
from (select *, row_number() over (partition by company order by salary) rk, count(company) over (partition by company) mi
from Employee ) a
where rk>=mi/2 and rk<=countmi/2+1

 No.25 1841. League Statistics

 

# 没有力扣会员,不好写,搬运博主的解法
SELECT 
    t.team_name,
    COUNT(*) AS 'matches_played', 
    SUM(
        CASE 
            WHEN (t.team_id=m.home_team_id AND m.home_team_goals>m.away_team_goals) OR
                (t.team_id=m.away_team_id AND m.home_team_goals<m.away_team_goals) THEN 3
            WHEN (t.team_id=m.home_team_id AND m.home_team_goals=m.away_team_goals) OR
                (t.team_id=m.away_team_id AND m.home_team_goals=m.away_team_goals) THEN 1
            WHEN (t.team_id=m.home_team_id AND m.home_team_goals<m.away_team_goals) OR
                (t.team_id=m.away_team_id AND m.home_team_goals>m.away_team_goals) THEN 0
        END
    ) AS 'points', 
    SUM(IF(t.team_id=m.home_team_id, m.home_team_goals, m.away_team_goals)) AS 'goal_for', 
    SUM(IF(t.team_id=m.home_team_id, m.away_team_goals, m.home_team_goals)) AS 'goal_against', 
    SUM(IF(t.team_id=m.home_team_id, m.home_team_goals, m.away_team_goals))-SUM(IF(t.team_id=m.home_team_id, m.away_team_goals, m.home_team_goals)) AS 'goal_diff'
FROM Teams t JOIN Matches m ON t.team_id=m.home_team_id OR t.team_id=m.away_team_id
GROUP BY team_id
ORDER BY points DESC, goal_diff DESC, team_name

 No.26 571. 给定数字的频率查询中位数

# 有点问题,需要重新思考
select avg(number)
from (select *, sum(Frequence) over (order by number) a from number  
     (row_number() over (order by Number ) b ) s1
     join 
     (select *, sum(Frequence) over (order by number) a from number ) s2 
     on s1.b=s2.number
where s1.a<=(count(s1.frequence)/2+1) and s2.a>=(count(s1.frequence)/2+1) 

No.27 618. 学生地理信息报告

在这里插入图片描述

#这题一开始确实没想法
# 核心思想是将最终生成表中的对应行数提前生成,方便后续按此来分组。MAX没有什么实际含义,只是可以用来聚合,MIN函数也行,而其他聚合函数如SUM函数的话会进行计数,所以不能用。
SELECT 
    MAX(IF(continent='America', name, NULL)) AS 'America',
    MAX(IF(continent='Asia', name, NULL)) AS 'Asia',
    MAX(IF(continent='Europe', name, NULL)) AS 'Europe'
FROM
    (SELECT *, ROW_NUMBER() OVER(PARTITION BY continent ORDER BY name) AS rn FROM student) AS t
GROUP BY rn

 No.28  1083. 销售分析 II

select distinct buyer_id
from sales 
where buyer_id in 
(select buyer_id 
from Sales,Product 
where Sales.product_id=Product.product_id and product_name='S8') 
and buyer_id not in 
(select buyer_id 
from Sales,Product 
where Sales.product_id=Product.product_id and product_name='iPhone')

 No.29 1205. 每月交易II

在这里插入图片描述

# 建立两张表,一张存放approved的订单信息,同时处理日期,另外一张存放被退单的订单信息,同时处理日期,使用union将两张表连接起来,存储在一张表中,再计算
SELECT 
    month, 
    country, 
    SUM(IF(state='approved', 1, 0)) AS approved_count,
    SUM(IF(state='approved', amount, 0)) AS approved_amount,
    SUM(IF(state='declined', 1, 0)) AS chargeback_count,
    SUM(IF(state='declined', amount, 0)) AS chargeback_amount 
FROM
(
    SELECT id, country, amount, state, DATE_FORMAT(trans_date, '%Y-%m') AS month FROM Transactions
    WHERE state<>'declined'
    UNION
    SELECT c.trans_id, t2.country, t2.amount, 'declined' as state, DATE_FORMAT(c.trans_date, '%Y-%m') AS month
    FROM Chargebacks c JOIN Transactions t2 ON t2.id=c.trans_id
) AS t
GROUP BY month, country

No.30 1501. 可以放心投资的国家

#使用having对分组的结果进行筛选,而不是用where语句,where语句无法与聚合函数一起使用。
#https://blog.csdn.net/bestforxu/article/details/51131234
#join on or 语句可用于生成需要对两列匹配的表
select name as country
from (SELECT id,co.name as name, duration
    FROM Person p join Country co on left(p.phone_number,3)=co.country_code
    JOIN Calls ca ON id=caller_id or id=callee_id ) s
group by name
having sum(duration)/count(id)>(select sum(duration)/count(caller_id) from Calls)

 No.311821. 寻找今年具有正收入的客户

select customer_id
from Customers
where year='2021' and revenue>0

No.32 1204. 最后一个能进入电梯的人

 

# 将符合要求的队列倒排序,第一个人就是题目要求的最后进入的人,用limit函数求得
select s1.person_name
from (select person_name, turn,sum(weight)over(order by turn) w from Queue ) s1
where w<=1000
order by turn desc
limit 1

## 如果所有人都能进入的话,以下这段代码就有问题
select s1.person_name
from (select person_name, turn,sum(weight)over(order by turn) w from Queue ) s1
join (select turn,sum(weight) over (order by turn) as n from Queue ) s2 
on s1.turn=s2.turn-1
where w<=1000 and s2.n>1000 

 No.33 1082. 销售分析 I 

#学会了使用all函数
select seller_id
from  Sales
group by seller_id 
having  sum(price)>=all(select sum(price) from sales group by seller_id)

No.34 1098. 小众书籍

# left join 和 ifull 很重要
select s1.book_id,s1.name
from Books s1 
left join Orders s2
on s1.book_id=s2.book_id and dispatch_date>='2018-06-23'
where s1.available_from<='2019-05-23' 
group by s1.book_id
having ifnull(sum(quantity),0) < 10

 NO.35 1270. 向公司CEO汇报工作的所有人

 

select distinct employee_id
from Employees 
where employee_id!=1 and manager_id in 
(
    select employee_id from employees where manager_id in 
    (select employee_id from employees where manager_id=1)

)

 No.36 597. 好友申请 I:总体通过率

#注意使用ifnull函数
#distinct A,B 可以实现多列去重
 select round (
     ifnull
        (
            (select count(distinct requester_id, accepter_id) from RequestAccepted) / 
            (select count(distinct sender_id,send_to_id) from FriendRequest)
            ,0),2
) as accept_rate

 No.37  1193. 每月交易 I

 

select month,country,count(id) as trans_count, sum(if(state='approved',1,0)) as approved_count,sum(amount) as trans_total_amount, sum(if(state='approved',amount,0)) as approved_total_amount
from (select *, DATE_FORMAT(trans_date, '%Y-%m') AS month from Transactions ) s1
group by month,country

 No.38 1280. 学生们参加各科测试的次数

#用“cross join”笛卡尔积和left join, 实现每个学生的科目都存在
select s1.student_id,s1.student_name,s1.subject_name, ifnull(count(e.student_id),0) as attended_exams
from (  select * 
        from students 
        cross join subjects) s1
left join examinations e
on s1.student_id=e.student_id and s1.subject_name=e.subject_name
group by s1.student_id, s1.subject_name
order by s1.student_id,s1.subject_name

 No.39  1715. 苹果和橘子的个数

#对小箱要使用ifnull,不然会报错
select (sum(b.apple_count)+sum(ifnull(c.apple_count,0)))as apple_count, (sum(b.orange_count) +sum(ifnull(c.orange_count,0)) )as orange_count
from Boxes b
left join Chests c on b.chest_id=c.chest_id

No.40 1809. 没有广告的剧集

select session_id
from playback
where session_id not in 
(select session_id from playback p join Ads a on p.customer_id=a.customer_id and a.timestamp>=start_time and a.timestamp<=end_time)

 No.41 577. 员工奖金

select name,bonus
from employee e
left join bonus b on e.empid=b.empid
where ifnull(bonus,0)<1000 

NO.42  603. 连续空余座位

#用abs简单
select distinct c1.seat_id
from cinema c1, cinema c2 
where abs(c1.seat_id-c2.seat_id)=1 and c1.free=1 and c2.free=1
order by c1.seat_id

No.43 1112. 每位学生的最高成绩

#窗口函数比较简单
select student_id,course_id,grade
from  (select *,row_number() over(partition by student_id order by grade desc, course_id) rk from enrollments) s1
where rk=1
group by student_id

 No.44 1308. 不同性别每日分数总计

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

#窗口函数yyds
select gender,day,sum(score_points) over(partition by gender order by day) as total
from scores
order by gender,day

 No.45 570. 至少有5名直接下属的经理

select name
from employee 
where id in (select managerId from Employee group by managerId having count(managerId)>=5)

No.46 580. 统计各专业学生人数 

在这里插入图片描述

在这里插入图片描述

#order 可以对select中的结果进行排序
select d.dept_name,ifnull(count(student_id),0) as student_number
from department d 
left join student s 
on d.dept_id=s.dept_id
group by d.dept_id
order by student_number desc, d.dept_name

 No.47 1407. 排名靠前的旅行者

 在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

select name, ifnull(sum(distance),0) as travelled_distance
from users 
left join rides
on users.id=rides.user_id
group by rides.user_id
order by travelled_distance desc, name

No.48  1795. 每个产品在不同商店的价格

在这里插入图片描述

在这里插入图片描述

select *
from 
(
    select product_id,'store1' as store,store1 as price from products
    union 
    select product_id,'store2' as store,store2  as price from products
    union
    select product_id,'store3' as store,store3 as price from products
) s1
where price<>0 or store<>Null
order by store

No.49 游戏玩法分析IV

在这里插入图片描述

在这里插入图片描述

select round (count(distinct player_id)/(select count(distinct player_id) from Activity),2) as fraction
from 
(select *, rank() over(partition by player_id order by event_date) rk, 
 lead(event_date,1) over(partition by player_id order by event_date) nextday 
from Activity) s1 
where datediff(event_date, nextday)=-1 and rk=1

No.50  579. 查询员工的累计薪水

在这里插入图片描述在这里插入图片描述 在这里插入图片描述

#题意比较难理解,首先排除最近一个月(即最大月)之外,剩下每个月的近三个月的累计薪水(不足三个月也要计算)
#两段不连续的月份也要按以上规则计算
SELECT t1.Id,t1.Month, SUM(t2.Salary) Salary
FROM Employee t1 JOIN Employee t2
ON t1.Id=t2.Id AND t1.Month>=t2.Month AND t1.Month-t2.month<3
WHERE (t2.Id, t2.Month) NOT IN (SELECT Id, MAX(Month) FROM Employee GROUP BY Id)  AND (t1.Id, t1.Month) NOT IN (SELECT Id, MAX(Month) FROM Employee GROUP BY Id)
GROUP BY t1.Id,t1.Month
ORDER BY t1.Id, t1.Month DESC


一周练完不快不慢吧,好久不编代码有点手生,练完50道之后就好很多了 。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值