牛客网SQL刷题笔记(MySQL)

此博客集合LeetCode、牛客网常见的题型及其解法,侵删

目录

  • 牛客网SQL刷题笔记(MySQL)
    • 类型1:查找排名第几的数据
      • SQL2 查找入职员工时间排名倒数第三的员工所有信息
      • SQL12 获取每个部门中当前员工薪水最高的相关信息
      • SQL17 获取当前薪水第二多的员工的emp_no以及其对应的薪水salary
      • SQL18 获取当前薪水第二多的员工的emp_no以及其对应的薪水salary
      • leecode176 第二高的薪水
      • leecode177 第N高的薪水
      • SQL90 获得积分最多的人(二)
      • SQL91 获得积分最多的人(三)
    • 类型2:三表连接
      • SQL19 查找所有员工的last_name和first_name以及对应的dept_name
      • SQL21 查找在职员工自入职以来的薪水涨幅情况
      • SQL22 统计各个部门的工资记录数
      • SQL38 返回顾客名称和相关订单号以及每个订单的总价(SQL必知必会)
      • SQL41 确定最佳顾客的另一种方式(二)(SQL必知必会)
    • 类型3:排序窗口函数
      • SQL23 对所有员工的薪水按照salary降序进行1-N的排名
      • LeetCode185 部门工资前三高的所有员工
    • 类型4:条件函数case when
      • 网易2018实习生招聘笔试题
      • SQL59 获取有奖金的员工相关信息
      • SQL36 知乎问答高质量的用户属于各级别的数量
    • 类型5:累计求和(sum)窗口函数
      • SQL60 统计salary的累计和running_total
    • 类型6:交叉连接(笛卡儿积)
      • leetcode181 超过经理薪水的员工
      • LeetCode197 上升的温度
      • LeetCode196 删除重复的电子邮箱
    • 类型7:用户连续登陆N天问题
      • SQL39 某乎问答最大连续回答问题天数大于等于3天的用户及其对应等级
      • SQL29 某宝店铺连续2天及以上购物的用户及其对应的天数
    • 类型8:中位数问题
      • SQL88 SQL88 最差是第几名(二)
  • 更新于2022/4/9

类型1:查找排名第几的数据

SQL2 查找入职员工时间排名倒数第三的员工所有信息

题目:请你查找employees里入职员工时间排名倒数第三的员工所有信息。
注意:可能会存在同一个日期入职的员工,所以入职员工时间排名倒数第三的员工可能不止一个。
员工employees表简况如下:

emp_no birth_date first_name last_name gender hire_date
10001 1953-09-02 Georgi Facello M 1986-06-26
10002 1964-06-02 Bezalel Simmel F 1985-11-21
10003 1959-12-03 Parto Bamford M 1986-08-28
10004 1954-05-01 Christian Koblick M 1986-12-01
解法1:子查询+distinct。
select * from employees
where hire_date = (select distinct hire_date
from employees
order by hire_date desc limit 2,1)

解法2:子查询+group by,目前大部分情况最好用group by,因为group by比distinct快的多。

select * from employees
where hire_date = (select hire_date
from employees
group by hire_date
order by hire_date desc limit 2,1)

SQL12 获取每个部门中当前员工薪水最高的相关信息

题目:获取每个部门中当前员工薪水最高的相关信息,给出dept_no, emp_no以及其对应的salary,按照部门编号dept_no升序排列。

类似的题目:leetcode:查询每个部门工资最多的员工

员工表dept_emp简况如下:

emp_no dept_no from_date to_date
10001 d001 1986-06-26 9999-01-01
10002 d001 1996-08-03 9999-01-01
10003 d002 1990-08-05 9999-01-01

薪水表salaries简况如下:

emp_no salary from_date to_date
1001 88958 2002-06-22 9999-01-01
1002 72527 2001-08-22 9999-01-01
1003 43311 2001-12-01 9999-01-01

解法:因为每个部门可能有多个最大的salary,因此在第一层查询中不要包括员工的信息,先求出每个部门最大的salary及其对应的dept_no。

select dept_no,max(salary)
from dept_emp join salaries on dept_emp.emp_no=salaries.emp_no
where salaries.to_date='9999-01-01' and dept_emp.to_date='9999-01-01'
group by dept_no

再用查找到的记录来对应emp_no。

select dept_emp.dept_no,dept_emp.emp_no,salary as maxSalary
from dept_emp join salaries on dept_emp.emp_no=salaries.emp_no
where (dept_no,salary) in (select dept_no,max(salary)
from dept_emp join salaries on dept_emp.emp_no=salaries.emp_no
where salaries.to_date='9999-01-01' and dept_emp.to_date='9999-01-01'
group by dept_no)
ORDER by dept_no

SQL17 获取当前薪水第二多的员工的emp_no以及其对应的薪水salary

题目:请你获取薪水第二多的员工的emp_no以及其对应的薪水salary,
若有多个员工的薪水为第二多的薪水,则将对应的员工的emp_no和salary全部输出,并按emp_no升序排序。
薪水表salaries简况如下:

emp_no salary from_date to_date
1001 88958 2002-06-22 9999-01-01
1002 72527 2001-08-22 9999-01-01
1003 43311 2001-12-01 9999-01-01

解法1:子查询+distinct筛选出排名第几的值,然后返回去寻找emp_no。解法和此题一样:SQL2 查找入职员工时间排名倒数第三的员工所有信息

select emp_no, salary
FROM salaries
where to_date = '9999-01-01'
and salary = (select distinct salary
from salaries
order by salary desc
limit 1,1)

解法2:子查询+group by

select emp_no, salary
FROM salaries
where to_date = '9999-01-01'
and salary = (select salary
from salaries
group by salary
order BY salary desc
limit 1,1)

SQL18 获取当前薪水第二多的员工的emp_no以及其对应的薪水salary

请你查找薪水排名第二多的员工编号emp_no、薪水salary、last_name以及first_name,不能使用order by完成
员工表employees简况如下:

emp_no birth_date first_name last_name gender hire_date
10001 1953-09-02 Georgi Facello M 1986-06-26
10002 1964-06-02 Bezalel Simmel F 1985-11-21
10003 1959-12-03 Parto Bamford M 1986-08-28
10004 1954-05-01 Christian Koblick M 1986-12-01

薪水表salaries简况如下:

emp_no salary from_date to_date
1001 88958 2002-06-22 9999-01-01
1002 72527 2001-08-22 9999-01-01
1003 43311 2001-12-01 9999-01-01
1004 74057 2001-11-27 9999-01-01

解法:内连接+子查询+max嵌套,先查找表中最大的salary,再找小于这个salary的最大的值,如果题目改为查排名第三那就再嵌套一层。

select salaries.emp_no
,max(salary)
,employees.last_name
,employees.first_name
from employees join salaries
on employees.emp_no=salaries.emp_no
where salary<(select max(salary) from salaries)

leecode176 第二高的薪水

题目:编写一个 SQL 查询,获取并返回 Employee 表中第二高的薪水 。如果不存在第二高的薪水,查询应该返回 null。
题目链接,点此进入

这里用判断空值的函数(ifnull)函数来处理特殊情况。
ifnull(a,b)函数解释:
如果value1不是空,结果返回a
如果value1是空,结果返回b

分析:因为此题结果只需要salary的值,所以不需要子查询,直接输出salary即可,另外,利用ifnull来判断是否存在第二高的薪水。
解法一:distinct

select ifNull((
select distinct Salary
from Employee
order by Salary desc limit 1,1),null) as SecondHighestSalary

解法一:group by

select ifNull((select salary
from employee
group by salary
order by salary desc
limit 1,1),Null) as SecondHighestSalary

leecode177 第N高的薪水

题目:编写一个SQL查询来报告 Employee 表中第 n 高的工资。如果没有第 n 个最高工资,查询应该报告为 null。
题目链接,点此进入

解法:排名第N高意味着要跳过N-1个薪水,由于无法直接用limit N-1,所以需先在函数开头处理N为N=N-1。

CREATE FUNCTION getNthHighestSalary(N INT) RETURNS INT
BEGINset N=N-1;RETURN (# Write your MySQL query statement below.select ifNull((select salaryfrom employee group by salary order by salary desc limit N,1),Null) as getNthHighestSalary);
END

SQL90 获得积分最多的人(二)

题目:请你写一个SQL查找积分增加最高的用户的id(可能有多个),名字,以及他的总积分是多少,查询结果按照id升序排序,以上例子查询结果如下:
题目链接,点此进入

id name grade_num
1 tm 4
3 zk 4

我的一个错误写法:想法是先利用子查询查出最大的grade_num,然后连接grade_info表和user表,最后根据grade_name来查找出id和name,思路问题不大,写法有问题。
此处最大的问题就是where的问题,where后面的grade_num会被认为是grade_info表和user表中自带的grade_num,而不是sum(grade_num)。

select id,name, sum(grade_num) as grade_num from
grade_info join user on grade_info.user_id=user.id
where grade_num =(select a from
(select id, name, sum(grade_num) as a
from grade_info
join user on grade_info.user_id=user.id
group by id,name
order by a desc
limit 1) t2)
group by id,name

正确写法:先把目标表列好,然后一个where进行筛选即可

select id, name, grade_name from
(select id,name, sum(grade_num) as grade_name from
grade_info join user on grade_info.user_id=user.id
group by id,name) t1
where grade_name =(select a from
(select id, name, sum(grade_num) as a
from grade_info
join user on grade_info.user_id=user.id
group by id,name
order by a desc
limit 1) t2)

解法二:利用with,用T作为临时表,然后用T和user连接,而不是用grade_info和user连接。

with T as
(select user_id, sum(grade_num) as grade_num
from grade_info
group by user_id)select id, name, grade_num
from T
join user on T.user_id=user.id
where grade_num=(select max(grade_num) from T)

SQL91 获得积分最多的人(三)

题目链接,点此进入
此题相比上题而言,多了一个add和reduce来让用户的积分有增有减。

解法:和上题一样,利用with简化写法,用case when来量化add和reduce

with T as
(select user_id, sum(a) as grade_num from
(select user_id, case when type='add' then grade_num*1else grade_num*(-1) end as a
from grade_info) t
group by user_id)select id, name, grade_num
from T
join user on T.user_id=user.id
where grade_num=(select max(grade_num) from T)
order by id

类型2:三表连接

SQL19 查找所有员工的last_name和first_name以及对应的dept_name

题目:请你查找所有员工的last_name和first_name以及对应的dept_name,也包括暂时没有分配部门的员工
员工表employees简况如下:

emp_no birth_date first_name last_name gender hire_date
10001 1953-09-02 Georgi Facello M 1986-06-26
10002 1964-06-02 Bezalel Simmel F 1985-11-21
10003 1959-12-03 Parto Bamford M 1986-08-28
10004 1954-05-01 Christian Koblick M 1986-12-01

部门表departments表简况如下:

dept_no dept_name
d001 Marketing
d002 Finance
d003 Human Resources

部门员工关系表dept_emp简况如下:

emp_no dept_no from_date to_date
10001 d001 1986-06-26 9999-01-01
10002 d001 1996-08-03 9999-01-01
10003 d002 1990-08-05 9999-01-01

解法:题目中提到要包括暂时没有分配部门的员工,因此运用两次left join连接嵌套。我们先看实例中第一行的顺序分别为last_name、first_name和dept_name,然后先找last_name、first_name所在的表为employees,再看dept_name在表departments中,但是表employees和表departments没有连接字段,因此两表中间要用dept_emp作为桥梁。表连接的顺序为employees-dept_emp-departments。

1、第一次left
join连接employees表与dept_emp表,得到所有员工的last_name和first_name以及对应的dept_no,也包括暂时没有分配部门的员工

2、第二次left
join连接上表与departments表,即连接dept_no与dept_name,得到所有员工的last_name和first_name以及对应的dept_name,也包括暂时没有分配部门的员工

select employees.last_name, employees.first_name, dept_name
from employees
left join dept_emp
on employees.emp_no=dept_emp.emp_no
left join departments
on dept_emp.dept_no=departments.dept_no

结果:

last_name first_name dept_name
Facello Georgi Marketing
Simmel Bezalel Marketing
Bamford Parto Finance
Koblick Chirstian NULL

SQL21 查找在职员工自入职以来的薪水涨幅情况

请你查找在职员工自入职以来的薪水涨幅情况,给出在职员工编号emp_no以及其对应的薪水涨幅growth,并按照growth进行升序。
题目链接,点此进入
员工表employees简况如下:

emp_no birth_date first_name last_name gender hire_date
10001 1953-09-02 Georgi Facello M 2001-06-22
10002 1964-06-02 Bezalel Simmel F 1999-08-03

薪水表salaries简况如下:

emp_no salary from_date to_date
10001 85097 2001-06-22 2002-06-22
10001 88958 2002-06-22 9999-01-01
10002 72527 1999-08-03 2000-08-02
10002 72527 2000-08-02 2001-08-02

解法一:把salaries作为两个表(h和t),构成了三表连接(employees,h,t),然后直接利用join来连接。

select employees.emp_no, t.salary-h.salary as growth
from employees
join salaries as h on employees.emp_no=h.emp_no
and employees.hire_date=h.from_date
join salaries as t on employees.emp_no=t.emp_no
and t.to_date='9999-01-01'
order by growth

解法二:先找出入职工资和离职工资的表,然后两表利用join连接,计算出离职工资减去入职工资。

select a.emp_no, b.t_salary-a.h_salary as growth
from
(select employees.emp_no, salary as h_salary
from employees join salaries on employees.emp_no=salaries.emp_no
where from_date=hire_date) as a join
(select employees.emp_no, salary as t_salary
from employees join salaries on employees.emp_no=salaries.emp_no
where to_date='9999-01-01') as b on a.emp_no=b.emp_no
order by growth

输出结果如下:

emp_no growth
10001 3861

SQL22 统计各个部门的工资记录数

题目:请你统计各个部门的工资记录数,给出部门编码dept_no、部门名称dept_name以及部门在salaries表里面有多少条记录sum,按照dept_no升序排序。
部门表departments简况如下:

dept_no dept_name
d001 Marketing
d002 Finance

部门员工关系表dept_emp简况如下:

emp_no dept_no from_date to_date
10001 d001 1986-06-26 9999-01-01
10002 d001 1996-08-03 9999-01-01
10003 d002 1990-08-05 9999-01-01

薪水表salaries简况如下:

emp_no salary from_date to_date
1001 85097 2001-06-22 2002-06-22
1001 88958 2002-06-22 9999-01-01
1002 72527 1996-08-03 9999-01-01
1003 32323 1996-08-03 9999-01-01

解法:如上题(SQL19)所述,先按结果的表头来找dept_no、dept_name、sum(薪水数总和)各自存在的表,然后进行三表连接的排序,顺序为departments-dept_emp-salaries。

select departments.dept_no, departments.dept_name
,count(salary) as sum
from departments
join dept_emp
on departments.dept_no=dept_emp.dept_no
join salaries
on dept_emp.emp_no=salaries.emp_no
group by dept_no
order by dept_no

结果:

dept_no dept_name sum
d001 Marketing 3
d002 Finance 1

SQL38 返回顾客名称和相关订单号以及每个订单的总价(SQL必知必会)

题目:除了返回顾客名称和订单号,返回 Customers 表中的顾客名称(cust_name)和Orders 表中的相关订单号(order_num),添加第三列 OrderTotal,其中包含每个订单的总价,并按顾客名称再按订单号对结果进行升序排序。
解法:三表连接+group by,依然按前面所述,确定好三表连接的顺序,然后进行分组和排序。
题目链接,点此进入

此题最关键的是group by,很容易忽略掉order_num,然后会报错,虽然此题的cust_name和order_num是一一对应的,但如果是一对多的关系,就不能准确的进行分组。此处不仅要根据cust_name分组,还要根据order_num来进行分组。
因此,解决方案:看最终要求来判断哪几个来进行分组,比如此题,最终结果的表头是cust_name,order_num和OrderTotal,那就根据cust_name,order_num来进行分组。

select Customers.cust_name
,Orders.order_num
,sum(quantity*item_price) as OrderTotal
from Customers
join Orders
on Customers.cust_id=Orders.cust_id
join OrderItems
on Orders.order_num=OrderItems.order_num
group by cust_name, order_num
order by cust_name, order_num

SQL41 确定最佳顾客的另一种方式(二)(SQL必知必会)

题目:编写 SQL 语句,返回订单总价不小于1000 的客户名称和总额(OrderItems 表中的order_num)。
提示:需要计算总和(item_price 乘以 quantity)。按订单号对结果进行排序,请使用INNER JOIN 语法。
题目链接,点此进入
解法:和SQL38(返回顾客名称和相关订单号以及每个订单的总价)解法差不多,但是group by有差异,此题需要最终结果的表头是cust_name和total_price,因此只需要对cust_name进行分组。

select cust_name
,sum(item_price*quantity) as total_price
from Customers
join Orders on Customers.cust_id=Orders.cust_id
join OrderItems on Orders.order_num=OrderItems.order_num
group by cust_name
having sum(item_price*quantity)>=1000
order by cust_name

类型3:排序窗口函数

排序窗口函数语法:over([partition by 字段名] [order by 字段名 asc|desc])

三种用于进行排序的专用窗口函数:
1、RANK()
在计算排序时,若存在相同位次,会跳过之后的位次。
例如,有3条排在第1位时,排序为:1,1,1,4······
2、DENSE_RANK()
这就是题目中所用到的函数,在计算排序时,若存在相同位次,不会跳过之后的位次。
例如,有3条排在第1位时,排序为:1,1,1,2······
3、ROW_NUMBER()
这个函数赋予唯一的连续位次。
例如,有3条排在第1位时,排序为:1,2,3,4······

偏移窗口函数语法:lag(字段名,偏移量[,默认值])over()

SQL23 对所有员工的薪水按照salary降序进行1-N的排名

题目:对所有员工的薪水按照salary降序先进行1-N的排名,如果salary相同,再按照emp_no升序排列。
题目链接,点此进入
薪水表salaries简况如下:

emp_no salary from_date to_date
1001 88958 2002-06-22 9999-01-01
1002 72527 2001-08-02 9999-01-01
1003 43311 2001-12-01 9999-01-01
1004 72527 2001-12-01 9999-01-01

解法:直接套用排序函数,不需要分区(partition by),如果是要求每个部门的排序就要进行分区。

select emp_no
,salary
,dense_rank()over(order by salary desc) as t_rank
from salaries

LeetCode185 部门工资前三高的所有员工

题目:公司的主管们感兴趣的是公司每个部门中谁赚的钱最多。一个部门的 高收入者是指一个员工的工资在该部门的 不同工资中排名前三 。编写一个SQL查询,找出每个部门中收入高的员工,以任意顺序返回结果表。
题目链接,点此进入

解法:这是两表连接且排序的问题,先利用join将两个表进行连接,然后对总表进行分组排序,上述操作构成一个新表a(mysql要求每一个派生出来的表都必须有一个自己的别名)。

select Department.name as Department
,Employee.name as Employee
,Salary
,dense_rank()over(partition by departmentId
order by salary desc) as rk
from Employee
join Department on Employee.departmentId=Department.id

最后从新表a中来选取所需要的数据。

select Department, Employee, Salary
from (select Department.name as Department
,Employee.name as Employee
,Salary
,dense_rank()over(partition by departmentId
order by salary desc) as rk
from Employee
join Department on Employee.departmentId=Department.id) as a
where rk<=3

类型4:条件函数case when

语法:case when
case expr when v1 then r1 [when v2 then r2] …[else rn] end
例1:case 2 when 1 then ‘one’ when 2 then ‘two’ else ‘more’ end 返回two
case后面的值为2,与第二条分支语句when后面的值相等相等,因此返回two
例2:case when v1 then r1 [when v2 then r2]…[else rn] end
例如:case when 1<0 then ‘T’ else ‘F’ end返回F
1<0的结果为false,因此函数返回值为else后面的F

网易2018实习生招聘笔试题

题目链接,点此进入
题目:好评率是会员对平台评价的重要指标。现在需要统计2018年1月1日到2018年1月31日,用户’小明’提交的母婴类目"花王"品牌的好评率(好评率=“好评”评价量/总评价量):
用户评价详情表:a
字段:id(评价id,主键),create_time(评价创建时间,格式’2017-01-01’), user_name(用户名称),goods_id(商品id,外键) ,
sub_time(评价提交时间,格式’2017-01-01 23:10:32’),sat_name(好评率类型,包含:“好评”、“中评”、“差评”)
商品详情表:b
字段:good_id(商品id,主键),bu_name(商品类目), brand_name(品牌名称)

select sum(case when sat_time = '好评' then 1 else 0 end)/count(sat_time) as "好评率"
from a join b on a.good_id = b.good_id
where user_name = '小明'
and (sub_time between '2017-1-1' and '2017-1-31')
and bu_name ='母婴'
and brand_name = '花王'

SQL59 获取有奖金的员工相关信息

bonus类型btype为1其奖金为薪水salary的10%,btype为2其奖金为薪水的20%,其他类型均为薪水的30%。 to_date='9999-01-01’表示当前薪水。
请你给出emp_no、first_name、last_name、奖金类型btype、对应的当前薪水情况salary以及奖金金额bonus。
bonus结果保留一位小数,输出结果按emp_no升序排序。
题目链接,点此进入
解法:简单的case when+三表连接的问题

select employees.emp_no, employees.first_name, employees.last_name
,emp_bonus.btype, salaries.salary
,(case when btype=1 then salary*0.1 when btype=2 then salary*0.2 else salary*0.3 end) as bonus
from employees join emp_bonus on employees.emp_no=emp_bonus.emp_no
join salaries on emp_bonus.emp_no=salaries.emp_no
where to_date='9999-01-01'
order by emp_no

SQL36 知乎问答高质量的用户属于各级别的数量

题目:回答字数大于等于100字的认为是高质量回答,请你统计某乎问答高质量的回答中用户属于1-2级、3-4级、5-6级的数量分别是多少,按数量降序排列
题目链接,点此进入

select
(case when author_level in (1,2) then '1-2级'when author_level in (3,4) then '3-4级'when author_level in (5,6) then '5-6级'end) as level_cut
, count(char_len) as num
from author_tb
join answer_tb
on author_tb.author_id=answer_tb.author_id
where char_len>=100
group by level_cut
order by num desc
level_cut num
5-6级 12
3-4级 2
1-2级 1

类型5:累计求和(sum)窗口函数

语法:sum(字段名1) over(partition by 字段名2 order by 字段名3 asc/desc)

SQL60 统计salary的累计和running_total

题目:按照salary的累计和running_total,其中running_total为前N个当前( to_date = ‘9999-01-01’)员工的salary累计和,其他以此类推。
题目链接,点此进入

select emp_no
,salary
,sum(salary)over(order by emp_no)as running_total
from salaries
where to_date='9999-01-01'

结果如下:

类型6:交叉连接(笛卡儿积)

leetcode181 超过经理薪水的员工

题目链接,点此进入
题目:编写一个SQL查询来查找收入比经理高的员工。
Employee表:

id name salary managerId
1 Joe 70000 3
2 Henry 80000 4
3 Sam 60000 null
4 Max 90000 null

解法1:自关联查询,先构建交叉链接,这是此类问题最主要的解法

select e1.Name as Employee
from Employee e1, Employee e2
where e1.ManagerId = e2.Id AND e1.Salary > e2.Salary
排序 id name salary managerId id name salary managerId
1 1 Joe 70000 3 1 Joe 70000 3
2 2 Henry 80000 4 1 Joe 70000 3
3 3 Sam 60000 null 1 Joe 70000 3
4 4 Max 90000 null 1 Joe 70000 3
5 1 Joe 70000 3 2 Henry 80000 4
6 2 Henry 80000 4 2 Henry 80000 4
7 3 Sam 60000 null 2 Henry 80000 4
8 4 Max 90000 null 2 Henry 80000 4
9 1 Joe 70000 3 3 Sam 60000 null
10 2 Henry 80000 4 3 Sam 60000 null
11 3 Sam 60000 null 3 Sam 60000 null
12 4 Max 90000 null 3 Sam 60000 null
13 1 Joe 70000 3 4 Max 90000 null
14 2 Henry 80000 4 4 Max 90000 null
15 3 Sam 60000 null 4 Max 90000 null
16 4 Max 90000 null 4 Max 90000 null

解法2:子查询

select e.name as 'Employee' from Employee e
where salary>(select salary from Employee where ID=e.managerID)

LeetCode197 上升的温度

题目:编写一个 SQL 查询,来查找与之前(昨天的)日期相比温度更高的所有日期的 id 。
返回结果 不要求顺序 。
题目链接,点此进入
Weather表:

id recordDate Temperature
1 2015-01-01 10
2 2015-01-02 25
3 2015-01-03 20
4 2015-01-04 30

step1:先构建交叉连接

序号 id recordDate Temperature id recordDate Temperature
1 1 2015-01-01 10 1 2015-01-01 10
2 2 2015-01-02 25 1 2015-01-01 10
3 3 2015-01-03 20 1 2015-01-01 10
4 4 2015-01-04 30 1 2015-01-01 10
5 1 2015-01-01 10 2 2015-01-02 25
6 2 2015-01-02 25 2 2015-01-02 25
7 3 2015-01-03 20 2 2015-01-02 25
8 4 2015-01-04 30 2 2015-01-02 25
9 1 2015-01-01 10 3 2015-01-03 20
10 2 2015-01-02 25 3 2015-01-03 20
11 3 2015-01-03 20 3 2015-01-03 20
12 4 2015-01-04 30 3 2015-01-03 20
13 1 2015-01-01 10 4 2015-01-04 30
14 2 2015-01-02 25 4 2015-01-04 30
15 3 2015-01-03 20 4 2015-01-04 30
16 4 2015-01-04 30 4 2015-01-04 30

setp2:datediff(日期1, 日期2):
得到的结果是日期1与日期2相差的天数。
如果日期1比日期2大,结果为正;如果日期1比日期2小,结果为负。

select a.id from weather as a join weather as b
on a.temperature>b.temperature
and datediff(a.recordDate,b.recordDate)=1

LeetCode196 删除重复的电子邮箱

题目:编写一个SQL查询来删除所有重复的电子邮件,只保留一个id最小的唯一电子邮件。以任意顺序返回结果表。
题目链接,点击进入
Person表如下:

id email
1 john@example.com
2 bob@example.com
3 john@example.com
Step1:先构建交叉连接
序号 id
1 1
2 2
3 3
4 1
5 2
6 3
7 1
8 2
9 3

Step2:对交叉连接的表进行观察并编写sql语句。

delete a from Person as a
join Person as b
on a.email=b.email
and a.id > b.id
#或者以下写法
delete a from Person a, Person b
where a.email=b.email and a.id>b.id

类型7:用户连续登陆N天问题

SQL39 某乎问答最大连续回答问题天数大于等于3天的用户及其对应等级

题目:知乎面试题
题目链接,点此进入
请你统计最大连续回答问题的天数大于等于3天的用户及其等级(若有多条符合条件的数据,按author_id升序排序),以上例子的输出结果如下:

author_id author_level days_cn
101 6 3

解法:参考此文章SQL-用户连续登陆问题

利用排序窗口函数进行解答,对登陆日期进行排序,如果某个用户连续登陆,那么他的登陆日期-序号是相等的。

select t2.author_id, author_level, t2.day_cnt from
(select author_id, count(*) day_cnt from
(select answer_date, author_id
, dense_rank()over(partition by author_id order by answer_date) as rk
from answer_tb
group by answer_date,author_id) t1 #去重
group by author_id, date_sub(answer_date, interval rk day)
having count(*)>=3) t2
join author_tb
on t2.author_id=author_tb.author_id
order by t2.author_id

SQL29 某宝店铺连续2天及以上购物的用户及其对应的天数

11月结束后,小牛同学需要对其在某宝的网店就11月份用户交易情况和产品情况进行分析以更好的经营小店。
11月份销售数据表sales_tb如下(其中,sales_date表示销售日期,user_id指用户编号,item_id指货号,sales_num表示销售数量,sales_price表示结算金额):

sales_date user_id item_id sales_num sales_price
2021-11-01 1 A001 1 90
2021-11-01 2 A002 2 220
2021-11-01 2 B001 1 120
2021-11-02 3 C001 2 500
2021-11-02 4 B001 1 120
2021-11-03 5 C001 1 240
2021-11-03 6 C002 1 270
2021-11-04 7 A003 1 180
2021-11-04 8 B002 1 140
2021-11-04 9 B001 1 125
2021-11-05 10 B003 1 120
2021-11-05 10 B004 1 150
2021-11-05 10 A003 1 180
2021-11-06 11 B003 1 120
2021-11-06 10 B004 1 150

请你统计连续2天及以上在该店铺购物的用户及其对应的次数(若有多个用户,按user_id升序排序),以上例子的输出结果如下:

user_id days_count
10 2

解法:和上题一样,用窗口函数进行排序然后用登陆日期减去序号

select user_id, count(*) as days_count from
(select sales_date, user_id
,dense_rank()over(partition by user_id order by sales_date) as rk
from sales_tb
group by sales_date, user_id) as t
group by user_id, date_sub(sales_date, interval rk day)
having count(*)>=2

类型8:中位数问题

SQL88 SQL88 最差是第几名(二)

题目链接,点此进入
题目:老师想知道学生们综合成绩的中位数是什么档位,请你写SQL帮忙查询一下,如果只有1个中位数,输出1个,如果有2个中位数,按grade升序输出,以上例子查询结果如下:

grade
B
C

解析:
总体学生成绩排序如下:A, A, B, B, B, B, C, C, C, C, D, D,总共12个数,取中间的2个,取6,7为:B,C

解法:首先我们需要知道:当某一数的正序和逆序累计均大于整个序列的数字个数的一半即为中位数

select grade
from
(select grade
, (select sum(number) from class_grade) as total
, sum(number)over(order by grade) as a
, sum(number)over(order by grade desc) as b
from class_grade) t
where a>=total/2 and b>=total/2
order by grade

更新于2022/4/9

牛客网SQL刷题笔记(MySQL)相关推荐

  1. 牛客网SQL刷题笔记总结

    非技术快速入门 1.基础查询 (1)基础查询 查询单列:查询所需的列名写在 SELECT 关键字之后,FROM 关键字指出从哪个表中查询数据. select device_id from user_p ...

  2. 牛客网java刷题笔记2019-1-4

    牛客网java刷题笔记 2019-1-4 1.java中可以用类中构造器调用其他类构造器(这个和C++中构造函数很类似)用于初始化程序变量值, 构造器和方法的区别: 功能和作用的不同 构造器是为了创建 ...

  3. sql里查询一个组和组的用户数怎么查?_【牛客网SQL刷题】留存率怎么算?

    抽空刷了牛客网SQL实战72题,最后几道以牛客网为例的题目还挺有挑战性,在此记录 统计时间段新用户次日留存率 每日的次日留存率 每日的新用户数 每日新用户的次日留存 求新登录用户次日留存 表login ...

  4. 牛客网SQL刷题问题汇总

    目录 1.选取字段为[奇数或偶数问题] 2.[排序问题] 3.MySQL[新建表.修改表] 4.对于表批量[插入数据],如果数据已经存在,则忽略 5.新建一个表,表中字段内容从另一个表导入 6.[索引 ...

  5. 牛客网SQL刷题四-电商场景(某东商城)

    SQL13 计算商城中2021年每月的GMV 数据 DROP TABLE IF EXISTS tb_order_overall; CREATE TABLE tb_order_overall (id I ...

  6. 牛客网SQL刷题二-某音短视频

    SQL1 各个视频的平均完播率 数据 DROP TABLE IF EXISTS tb_user_video_log, tb_video_info; CREATE TABLE tb_user_video ...

  7. 牛客网Java刷题知识点之关键字static、static成员变量、static成员方法、static代码块和static内部类...

    不多说,直接上干货! 牛客网Java刷题知识点之关键字static static代表着什么 在Java中并不存在全局变量的概念,但是我们可以通过static来实现一个"伪全局"的概 ...

  8. 牛客网Java刷题知识点之构造函数可以调用一般函数,但是一般函数不可以直接调用构造函数...

    不多说,直接上干货! 通过 牛客网Java刷题知识点之构造函数是什么.一般函数和构造函数什么区别呢.构造函数的重载.构造函数的内存图解 我们对构造函数有了一个比较清楚的认识,当我们在创建对象时,我们会 ...

  9. 牛客网Java刷题知识点之Java 集合框架的构成、集合框架中的迭代器Iterator、集合框架中的集合接口Collection(List和Set)、集合框架中的Map集合...

    不多说,直接上干货! 集合框架中包含了大量集合接口.这些接口的实现类和操作它们的算法. 集合容器因为内部的数据结构不同,有多种具体容器. 不断的向上抽取,就形成了集合框架. Map是一次添加一对元素. ...

最新文章

  1. 简单介绍互联网领域选择与营销方法
  2. 推荐:复旦邱锡鹏教授开源发布的《神经网络与深度学习》
  3. 最流行的python爬虫框架_Python最火爬虫框架Scrapy入门与实践
  4. 笨方法学python3怎么样_抖音笨李白是什么歌 抖音笨李白歌曲歌词介绍
  5. LQ训练营(C++)学习笔记_动态规划入门
  6. FineUICore基础版部署到docker实战
  7. leetcode 740. 删除并获得点数(dp)
  8. 开源大数据平台HBase对接OBS操作指南
  9. python3 manage.py runserver 0.0.0.0:8000 没反应
  10. 在哪里买铁甲格斗机器人_铁甲雄心Ⅱ火了 优必选“超变铁甲”掀起闯关赢免单热潮...
  11. 服装免费收银系统哪个好-云上铺会员管理软件
  12. 筛选法求100以内的素数
  13. 基于python对doi号通过sci-hub进行pubmed中的文献下载
  14. m6A甲基化及预测方法工具总结
  15. 现代信息检索——基本概念
  16. 未来的计算机能帮人类炒股,未来计算机能帮人类炒股吗
  17. 测试手机运行速度的软件,你的手机合格了吗 两款手机性能测试软件横评
  18. 打印表格留标题怎么设置_表格打印怎么保留标题!EXCEL打印如何设置每页都显示标题栏...
  19. A15处理器和m1哪个好
  20. 微波射频学习笔记17-------LC谐振的验证和LC滤波器原理

热门文章

  1. 微型四旋翼飞行器设计经验之瞎扯淡
  2. Lumerical官方案例、FDTD时域有限差分法仿真学习(四)——环形调制器 - 瞬态响应 (Ring modulator - transient response ,varFDTD)
  3. js进阶 - 收藏集 - 掘金
  4. 35-【什么叫规矩 什么叫体统】map容器
  5. 企业BI系统应用_证券公司运营数据分析系统
  6. matlab2015a可以做神经网络,语音学习笔记9------Matlab R2015a实现BP神经网络的嗓音识别...
  7. php k线15分钟 30分钟,妙用5分钟k线 ,浅谈短线方法:15分钟与30分钟k线图运用
  8. ctfshow web入门-反序列化
  9. 电脑服务器停止响应已经恢复,Win7系统提示“显示器驱动已停止响应并且已恢复”的解决方法...
  10. 信捷总线Xnet-速度模式使用总结