Leetcode SQL会员题【吐血总结~~】第一天

忍痛开了一个月会员,就是想刷一下leetcode的sql会员题,在这里也把刷题过程都记录下来,供大家一起学习,以下所有题目的答案以及思路都是本人亲自写的,有不对的地方欢迎大家评论讨论~

目录

511. 游戏玩法分析I
512. 游戏玩法分析II
534. 游戏玩法分析III
550. 游戏玩法分析IV
569. 员工薪水中位数
570. 至少有5名直接下属的经理
571. 给定数字的频率查询中位数
574. 当选者I
577. 员工奖金
578. 查询回答效率最高的问题
579. 查询员工的累计薪水
580. 统计各专业学生人数
585. 2016年的投资
597. 好友申请I: 总体通过率
602. 好友申请II: 谁有最多的好友
603. 连续空余座位
610. 判断三角形I

511. 游戏玩法分析I

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

  • 源代码:
    select player_id, min(event_date) as first_login
    from activity
    group by player_id;
    
  • 思路:题目要求每一个玩家对应的…,很明显按照player_id分组,想到这里应该就不难求出每位玩家的最早登陆日期

512. 游戏玩法分析II

在这里插入图片描述

  • 源代码:
    select player_id, device_id
    from activity
    where (player_id, event_date) in (
        select player_id, min(event_date)
        from activity
        group by player_id
    );
    
  • 思路:首先对需求拆解,第一步求出首次登录的用户,第二步,求出设备名称,有两个步骤所以可以考虑使用子查询的方式

534. 游戏玩法分析III

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

  • 源代码:
    select player_id, event_date, sum(games_played) over(partition by player_id order by event_date) as games_played_so_far
    from activity;
    
  • 思路:很明显,题目是一个求累计的过程,所以想到了开窗函数

550. 游戏玩法分析IV

在这里插入图片描述

  • 源代码:
    select round(count(*) / (select count(distinct player_id) from activity), 2)
    from (
        select player_id, date_sub(event_date, row_number() over(partition by player_id order event_date)) as diff  
        from activity
    )tmp
    group by player_id, diff
    having count(*) >= 2;
    
  • 思路:用户连续登陆问题,这是一个面试常考的SQL题,我们可以将每个用户按照日期进行排名,如果是连续登陆,那么日期减去排名得到的日期是相同的,我们只需要判断每个用户相同的有多少个,如果是两个,就是连续登陆两天的用户

569. 员工薪水中位数

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

  • 源代码:
    select id, company, salary
    from (
    select 
        id, 
        company, 
        row_number() over(partition by company order by salary) rk,
        count(*) over(partition by company) as total
    from employee
    ) tmp
    where tmp.rk in (floor((total + 1) / 2), floor((total + 2) / 2));
    
  • 思路:可以按照分组进行排名,然后如果当前分组数据行数为偶数条,就返回中间的两个排名的数据,否则,返回最中间的排名的数据

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

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

  • 源代码:
    select name 
    from employee 
    where id in (
        select managerId
        from (
            select managerId, count(*) cnt
            from employee
            group by managerId
        )t
        where cnt >= 5
    );
    
  • 思路:首先拆分需求,第一步,求出至少有5个直接下属的经理编号,第二步,求出对应的名字

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

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

  • 源代码:
    select avg(num) as median
    from (
        select 
            num,
            sum(frequency) over()  total, 
            sum(frequency) over(order by num)  sum_fre, 
            sum(frequency) over(order by num desc) as sum_fre_desc
        from numbers
    ) t
    where sum_fre >= total / 2 and sum_fre_desc >= total / 2;
    
  • 思路:这里就是用到了根据频数求中位数的技巧,我们将频数按照数字升序累加和逆序累加,然后取出升序和逆序频数累计都大于等于 总共累计的一半

574. 当选者

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

  • 源代码:
    with tmp as (
        select candidateid, count(id) cnt
        from vote
        group by candidateId
    )
    select name
    from tmp
    join candidate on tmp.candidateId = candidate.id
    where cnt = (
        select max(cnt)
        from tmp
    )
    
  • 思路:这种很显然需要求出每个候选人被投票的数量,建立一张临时表,以便后面多次使用到

577. 员工奖金

在这里插入图片描述

在这里插入图片描述

  • 源代码:
    select name, bonus
    from employee
    left join bonus
    on employee.empId = bonus.empId
    where bonus.bonus < 1000 or bonus.bonus is null;
    
  • 思路:我们应该了解 有些员工是没有奖金的,所以这一部分员工也符合题目的要求,需要输出

578. 查询回答率最高的问题

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

  • 源代码:
    with tmp as (
        select question_id, count(case action when "answer" then 1 end) / count(case action when "show" then 1 end) as rate
        from surveylog
        group by question_id
    )
    select question_id as survey_log 
    from tmp
    where rate = (
        select max(rate)
        from tmp
    )
    order by question_id
    limit 1;
    
  • 思路:先求出每个问题的回答率,然后再过滤出最大的回答率的问题

579. 查询员工的累计薪水

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

  • 源代码:
    select id, month, salary
    from (
        select 
        	 id,
        	 month, 
        	 sum(salary) over(partition by id order by month range 2 preceding) salary,
             row_number() over(partition by id order by month desc) r
        from employee
    )t
    where t.r > 1
    order by id, month desc;
    
  • 思路:本题的核心点其实不是去掉最后一个月,而是如何累计最近的3个月,range的用法我也是第一次使用,以前可能都是使用rows,这两者的区别是 range根据order by的字段进行累计,而rows根据行来进行累计

580. 统计各专业学生人数

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

  • 源代码:
    select dept_name, count(student_id) student_number
    from student stu 
    right join department dep
    on stu.dept_id = dep.dept_id
    group by dept_name
    order by student_number desc, dept_name;
    
  • 思路:本题的边界条件过于细致,真正的面试中给出大致的思路就可以了

585. 2016年的投资

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

  • 源代码:
    select round(sum(tiv_2016), 2) TIV_2016 
    from insurance
    join (
        select LAT, LON
        from insurance
        group by LAT, LON
        having count(*) <= 1
    )t1
    on insurance.LAT = t1.LAT and insurance.LON = t1.LON
    join (
        select tiv_2015
        from insurance
        group by tiv_2015
        having count(tiv_2015) >= 2
    )t2
    on insurance.tiv_2015 = t2.tiv_2015
    
  • 思路:分别对两个条件进行取数,然后和源表进行join

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

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

  • 源代码:
    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
    
  • 思路:理解需求,就是用通过的人数除以总人数,也就是要求通过的人数和总人数,总人数很清楚,就是friendrequest表,由于题目要求通过的人数只用统计requestaccepted表就可以了。

602. 好友申请 II :谁有最多的好友

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

  • 源代码:
    with tmp as (
        select id, sum(num) total
        from (
            select requester_id id, count(requester_id) num
            from requestaccepted
            group by requester_id
            union all
            select accepter_id id, count(accepter_id) num
            from requestaccepted
            group by accepter_id
        )t
        group by id
    )
    select id, total num
    from tmp
    where tmp.total = (
        select max(total)
        from tmp
    );
    
  • 思路:我们不仅需要按照发送好友的人进行聚合,而且还需要按照接收好友的人进行聚合,最后得到的都是一样的字段id, num,因此这个时候我就想到了union all可以将两个中间结果进行累加

603. 连续空余座位

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

  • 源代码:
    with tmp as (
        select seat_id, (seat_id - row_number() over(partition by free order by seat_id)) as diff
        from cinema
        where free = 1
    )
    select seat_id
    from tmp 
    where diff in (
        select diff
        from tmp
        group by diff
        having count(*) >= 2
    )
    
  • 思路:连续问题,开窗就可以了

610. 判断三角形

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

  • 源代码:
    select x, y, z, if((x + y > z) and (x + z > y) and (y + z > x), 'Yes', 'No') triangle
    from triangle
    
  • 思路:两边之和大于第三边

猜你喜欢

转载自blog.csdn.net/qq_42397330/article/details/123652086