高频 SQL 50 题(基础版)
2023-06-07 21:50:47 0 举报
AI智能生成
高频 SQL 50 题(基础版),数据分析、数据仓库手写必备
作者其他创作
大纲/内容
查询
1757. 可回收且低脂的产品
select
product_id
from Products
where low_fats = 'y' and recyclable ='Y'
product_id
from Products
where low_fats = 'y' and recyclable ='Y'
584. 寻找用户推荐人
SELECT name FROM customer WHERE referee_id <> 2 OR referee_id IS NULL;
SELECT name FROM customer WHERE referee_id != 2 OR referee_id IS NULL;
select name
from customer
where ifnull(referee_id,0) != 2
-- 不等于还可以这么写:<>
from customer
where ifnull(referee_id,0) != 2
-- 不等于还可以这么写:<>
595. 大的国家
way1:or
SELECT
name, population, area
FROM
world
WHERE
area >= 3000000 OR population >= 25000000
;
name, population, area
FROM
world
WHERE
area >= 3000000 OR population >= 25000000
;
way2:union
SELECT
name, population, area
FROM
world
WHERE
area >= 3000000
UNION
SELECT
name, population, area
FROM
world
WHERE
population >= 25000000
;
name, population, area
FROM
world
WHERE
area >= 3000000
UNION
SELECT
name, population, area
FROM
world
WHERE
population >= 25000000
;
1148. 文章浏览 I
way1:DISTINCT 和 ORDER BY
# Write your MySQL query statement below
select
distinct author_id as id
from Views where author_id = viewer_id
order by author_id
select
distinct author_id as id
from Views where author_id = viewer_id
order by author_id
1683. 无效的推文
# Write your MySQL query statement below
SELECT
tweet_id
FROM
tweets
WHERE
LENGTH(content) > 15;
SELECT
tweet_id
FROM
tweets
WHERE
LENGTH(content) > 15;
连接
1378. 使用唯一标识码替换员工ID
# Write your MySQL query statement below
select
unique_id
,name
from Employees a left join EmployeeUNI b using(id)
select
unique_id
,name
from Employees a left join EmployeeUNI b using(id)
# Write your MySQL query statement below
select
ifnull(unique_id,null) unique_id
,name
from Employees a left join EmployeeUNI b using(id)
select
ifnull(unique_id,null) unique_id
,name
from Employees a left join EmployeeUNI b using(id)
1068. 产品销售分析 I
way1:left join
select
p.product_name,
s.year,
s.price
from Sales s
left join Product p
on s.product_id=p.product_id
p.product_name,
s.year,
s.price
from Sales s
left join Product p
on s.product_id=p.product_id
1581. 进店却未进行过交易的顾客
way1:left join
SELECT customer_id, count(customer_id) count_no_trans
FROM Visits v
LEFT JOIN transactions t
ON v.visit_id = t.visit_id
WHERE transaction_id IS NULL
GROUP BY customer_id;
FROM Visits v
LEFT JOIN transactions t
ON v.visit_id = t.visit_id
WHERE transaction_id IS NULL
GROUP BY customer_id;
way2:not in
SELECT customer_id,count(visit_id) as count_no_trans
FROM Visits
WHERE visit_id not in (SELECT DISTINCT visit_id FROM Transactions)
GROUP BY customer_id
FROM Visits
WHERE visit_id not in (SELECT DISTINCT visit_id FROM Transactions)
GROUP BY customer_id
197. 上升的温度
方法一:lag()+datediff()
select id
from
(select
id,
temperature,
recordDate,
lag(recordDate,1) over(order by recordDate) as last_date,
lag(temperature,1) over(order by recordDate) as last_temperature
from Weather) a
where temperature > last_temperature and datediff(recordDate, last_date) = 1
from
(select
id,
temperature,
recordDate,
lag(recordDate,1) over(order by recordDate) as last_date,
lag(temperature,1) over(order by recordDate) as last_temperature
from Weather) a
where temperature > last_temperature and datediff(recordDate, last_date) = 1
方法二:笛卡尔积
select
b.Id
from
weather a
inner join
weather b
where
DATEDIFF(b.recordDate,a.recordDate)=1
and b.Temperature > a.Temperature;
b.Id
from
weather a
inner join
weather b
where
DATEDIFF(b.recordDate,a.recordDate)=1
and b.Temperature > a.Temperature;
方法三:TIMESTAMPDIFF()
select w1.Id
from Weather as w1, Weather as w2
where TIMESTAMPDIFF(DAY, w2.RecordDate, w1.RecordDate) = 1
AND w1.Temperature > w2.Temperature
from Weather as w1, Weather as w2
where TIMESTAMPDIFF(DAY, w2.RecordDate, w1.RecordDate) = 1
AND w1.Temperature > w2.Temperature
方法四:adddate()函数
select a.id
from weather a join weather b
on (a.recorddate = adddate(b.recorddate,INTERVAL 1 day))
where a.temperature > b.temperature
from weather a join weather b
on (a.recorddate = adddate(b.recorddate,INTERVAL 1 day))
where a.temperature > b.temperature
方法五:外连接+子查询+Date_ADD()函数
select
w.Id
from Weather w
join (
select
RecordDate,Temperature
from
Weather
) t1
on w.RecordDate = DATE_ADD(t1.RecordDate,INTERVAL 1 day)
where w.Temperature > t1.Temperature;
w.Id
from Weather w
join (
select
RecordDate,Temperature
from
Weather
) t1
on w.RecordDate = DATE_ADD(t1.RecordDate,INTERVAL 1 day)
where w.Temperature > t1.Temperature;
1661. 每台机器的进程平均运行时间
way1
select
machine_id,
round(avg(if(activity_type='start', -timestamp, timestamp))*2, 3) processing_time
from Activity
group by machine_id
machine_id,
round(avg(if(activity_type='start', -timestamp, timestamp))*2, 3) processing_time
from Activity
group by machine_id
way2
# Write your MySQL query statement below
select
machine_id
,round(sum((case when activity_type ='end' then timestamp else 0 end) - (case when activity_type ='start' then timestamp else 0 end))/count(distinct process_id ),3) as processing_time
from Activity
group by machine_id
select
machine_id
,round(sum((case when activity_type ='end' then timestamp else 0 end) - (case when activity_type ='start' then timestamp else 0 end))/count(distinct process_id ),3) as processing_time
from Activity
group by machine_id
577. 员工奖金
way1
# Write your MySQL query statement below
select
name,bonus
from Employee e left join Bonus b using(empId)
where bonus < 1000 or bonus is null;
select
name,bonus
from Employee e left join Bonus b using(empId)
where bonus < 1000 or bonus is null;
1280. 学生们参加各科测试的次数
way1:自连接构建临时表
# Write your MySQL query statement below
with aa as (
select * from Students,Subjects
)
select
aa.student_id
,aa.student_name
,aa.subject_name
,ifnull(count(s.subject_name),0) as attended_exams
from aa
left join Examinations s using(student_id,subject_name)
group by
aa.student_id
,aa.student_name
,aa.subject_name
order by aa.student_id,aa.student_name
with aa as (
select * from Students,Subjects
)
select
aa.student_id
,aa.student_name
,aa.subject_name
,ifnull(count(s.subject_name),0) as attended_exams
from aa
left join Examinations s using(student_id,subject_name)
group by
aa.student_id
,aa.student_name
,aa.subject_name
order by aa.student_id,aa.student_name
# 自连接
with cte1 as
(
select *
from students,subjects
)
select
a.student_id,
a.student_name,
a.subject_name,
ifnull(count(b.subject_name),0) as attended_exams
from cte1 a
left join Examinations b
using(student_id,subject_name)
group by 1,2,3
order by 1,2,3
作者:zg104
链接:https://leetcode.cn/problems/students-and-examinations/solution/by-zg104-0sww/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
with cte1 as
(
select *
from students,subjects
)
select
a.student_id,
a.student_name,
a.subject_name,
ifnull(count(b.subject_name),0) as attended_exams
from cte1 a
left join Examinations b
using(student_id,subject_name)
group by 1,2,3
order by 1,2,3
作者:zg104
链接:https://leetcode.cn/problems/students-and-examinations/solution/by-zg104-0sww/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
570. 至少有5名直接下属的经理
way1:使用临时表进行连接
SELECT
Name
FROM
Employee AS t1 JOIN
(SELECT
ManagerId
FROM
Employee
GROUP BY ManagerId
HAVING COUNT(ManagerId) >= 5) AS t2
ON t1.Id = t2.ManagerId
;
Name
FROM
Employee AS t1 JOIN
(SELECT
ManagerId
FROM
Employee
GROUP BY ManagerId
HAVING COUNT(ManagerId) >= 5) AS t2
ON t1.Id = t2.ManagerId
;
way2:managerid中出现至少5次的是哪些(group by+having 聚合函数) in
select Name
from Employee
where Id in
(
select distinct ManagerId
from Employee
group by ManagerID
having count(ManagerID)>=5
)
from Employee
where Id in
(
select distinct ManagerId
from Employee
group by ManagerID
having count(ManagerID)>=5
)
1934. 确认率
way1
# Write your MySQL query statement below
select
s.user_id
,round(
sum(if(c.action = 'confirmed',1,0)) /
count(s.user_id)
,2) as confirmation_rate
from Signups s left join Confirmations c using(user_id)
group by 1
select
s.user_id
,round(
sum(if(c.action = 'confirmed',1,0)) /
count(s.user_id)
,2) as confirmation_rate
from Signups s left join Confirmations c using(user_id)
group by 1
聚合函数
620. 有趣的电影
way1:使用 MOD() 函数
select *
from cinema
where mod(id, 2) = 1 and description != 'boring'
order by rating DESC
;
from cinema
where mod(id, 2) = 1 and description != 'boring'
order by rating DESC
;
way2:(id % 2) = 1来确定奇数
# Write your MySQL query statement below
select
id,movie,description,rating
from cinema
where description != 'boring'
and (id%2) = 1
order by rating desc;
select
id,movie,description,rating
from cinema
where description != 'boring'
and (id%2) = 1
order by rating desc;
1251. 平均售价
way1
select
p.product_id
,round((sum(units*price)/sum(units)),2) as average_price
from Prices p left join UnitsSold u on p.product_id = u.product_id
and purchase_date >= start_date
and purchase_date <= end_date
group by p.product_id
p.product_id
,round((sum(units*price)/sum(units)),2) as average_price
from Prices p left join UnitsSold u on p.product_id = u.product_id
and purchase_date >= start_date
and purchase_date <= end_date
group by p.product_id
1075. 项目员工 I
way1:avg
# Write your MySQL query statement below
select p.project_id, ROUND(AVG(e.experience_years), 2) as average_years
from Project p, Employee e
where p.employee_id = e.employee_id
group by p.project_id;
select p.project_id, ROUND(AVG(e.experience_years), 2) as average_years
from Project p, Employee e
where p.employee_id = e.employee_id
group by p.project_id;
way2:sum/count
# Write your MySQL query statement below
select
project_id
,round((sum(experience_years)/count(p.employee_id)),2) as average_years
from Project p
left join Employee e using(employee_id)
group by project_id
select
project_id
,round((sum(experience_years)/count(p.employee_id)),2) as average_years
from Project p
left join Employee e using(employee_id)
group by project_id
1633. 各赛事的用户注册率
way1
# Write your MySQL query statement below
select
contest_id
,round((100*count(user_id)/(select count(1) from Users))
,2) as percentage
from Register
group by contest_id
order by 2 desc,1 asc
select
contest_id
,round((100*count(user_id)/(select count(1) from Users))
,2) as percentage
from Register
group by contest_id
order by 2 desc,1 asc
1211. 查询结果的质量和占比
way1:
# Write your MySQL query statement below
select
query_name
,round((avg(rating/position)),2) as quality
,round((sum(if(rating < 3,1,0 ))/count(*)) *100,2) as poor_query_percentage
from Queries
group by query_name
select
query_name
,round((avg(rating/position)),2) as quality
,round((sum(if(rating < 3,1,0 ))/count(*)) *100,2) as poor_query_percentage
from Queries
group by query_name
1193. 每月交易 I
way1
# Write your MySQL query statement below
select
date_format(trans_date,'%Y-%m') as 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 Transactions
group by date_format(trans_date,'%Y-%m'),country
select
date_format(trans_date,'%Y-%m') as 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 Transactions
group by date_format(trans_date,'%Y-%m'),country
way2
# Write your MySQL query statement below
select
substr(trans_date,1,7) as 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 Transactions
group by substr(trans_date,1,7),country
select
substr(trans_date,1,7) as 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 Transactions
group by substr(trans_date,1,7),country
1174. 即时食物配送 II
way1:子查询
# Write your MySQL query statement below
select
round(sum(if(order_date=customer_pref_delivery_date,1,0))/
count(*)
*100,2) as immediate_percentage
from Delivery where (customer_id,order_date) in (
select customer_id,min(order_date) as order_date from Delivery
group by customer_id
)
select
round(sum(if(order_date=customer_pref_delivery_date,1,0))/
count(*)
*100,2) as immediate_percentage
from Delivery where (customer_id,order_date) in (
select customer_id,min(order_date) as order_date from Delivery
group by customer_id
)
550. 游戏玩法分析 IV
way1:子查询,分别确定分子分母
select
ifnull(round(
count(distinct player_id)/
(select count(distinct player_id) from Activity)
,2)
,0) as fraction
from Activity
where (player_id,event_date) in
(
select player_id,date(min(event_date)+1) from Activity
group by player_id
)
ifnull(round(
count(distinct player_id)/
(select count(distinct player_id) from Activity)
,2)
,0) as fraction
from Activity
where (player_id,event_date) in
(
select player_id,date(min(event_date)+1) from Activity
group by player_id
)
way2:inner join ,分别确定分子分母
select
round(
sum(if((datediff(a.event_date,b.first_date)=1),1,0)
)/(select count(distinct player_id) from Activity)
,2
) as fraction
from Activity a , (
select player_id,min(event_date) as first_date from Activity
group by player_id
) b where a.player_id = b.player_id
round(
sum(if((datediff(a.event_date,b.first_date)=1),1,0)
)/(select count(distinct player_id) from Activity)
,2
) as fraction
from Activity a , (
select player_id,min(event_date) as first_date from Activity
group by player_id
) b where a.player_id = b.player_id
way3:又学到了,配合布尔表达式
,把日期变为0或1,avg就可以对日期求平均值
b.event_date is not null此时已经是布尔值,
b.event_date != null 则为1,为null则为0,avg是对0或1求平均值
select
,把日期变为0或1,avg就可以对日期求平均值
b.event_date is not null此时已经是布尔值,
b.event_date != null 则为1,为null则为0,avg是对0或1求平均值
select
select
round(avg(b.event_date is not null),2) as fraction
from (select
player_id,min(event_date) as first_date
from Activity
group by player_id) a left join Activity b
on a.player_id=b.player_id and datediff(b.event_date,a.first_date)=1;
round(avg(b.event_date is not null),2) as fraction
from (select
player_id,min(event_date) as first_date
from Activity
group by player_id) a left join Activity b
on a.player_id=b.player_id and datediff(b.event_date,a.first_date)=1;
排序和分组
2356. 每位教师所教授的科目种类的数量
way1:
# Write your MySQL query statement below
select
teacher_id
,count(distinct subject_id) as cnt
from Teacher
group by 1
select
teacher_id
,count(distinct subject_id) as cnt
from Teacher
group by 1
1141. 查询近30天活跃用户数
way1:
# Write your MySQL query statement below
select
activity_date as day
,count(distinct user_id) as active_users
from
Activity
where datediff('2019-07-27',activity_date) < 30 and activity_date<='2019-07-27'
group by activity_date
select
activity_date as day
,count(distinct user_id) as active_users
from
Activity
where datediff('2019-07-27',activity_date) < 30 and activity_date<='2019-07-27'
group by activity_date
way2
# Write your MySQL query statement below
select activity_date day, count(distinct user_id) active_users
from Activity
where date_add(activity_date, interval 29 day)>='2019-07-27' and activity_date<='2019-07-27'
group by activity_date;
select activity_date day, count(distinct user_id) active_users
from Activity
where date_add(activity_date, interval 29 day)>='2019-07-27' and activity_date<='2019-07-27'
group by activity_date;
1084. 销售分析III
way1
# Write your MySQL query statement below
# 其实题目要求“仅在2019-01-01至2019-03-31之间出售的商品”翻译过来就是“所有售出日期都在这个时间内”,也就是“在这个时间内售出的商品数量等于总商品数量”,这样就不难写出这个语句
select
distinct
s.product_id
,p.product_name
from Sales s inner join Product p on s.product_id = p.product_id
and s.product_id not in (
select product_id from Sales where sale_date not between '2019-01-01' and '2019-03-31'
)
;
# 其实题目要求“仅在2019-01-01至2019-03-31之间出售的商品”翻译过来就是“所有售出日期都在这个时间内”,也就是“在这个时间内售出的商品数量等于总商品数量”,这样就不难写出这个语句
select
distinct
s.product_id
,p.product_name
from Sales s inner join Product p on s.product_id = p.product_id
and s.product_id not in (
select product_id from Sales where sale_date not between '2019-01-01' and '2019-03-31'
)
;
way2
# Write your MySQL query statement below
select
p.product_id,p.product_name
from Sales s,Product p
where s.product_id = p.product_id
group by p.product_id
having min(s.sale_date) >= '2019-01-01'
and max(s.sale_date) <= '2019-03-31';
select
p.product_id,p.product_name
from Sales s,Product p
where s.product_id = p.product_id
group by p.product_id
having min(s.sale_date) >= '2019-01-01'
and max(s.sale_date) <= '2019-03-31';
596. 超过5名学生的课
way1
# Write your MySQL query statement below
select class
from (select
class
,count(distinct student) as num
from Courses
group by class) as class
where num >=5
select class
from (select
class
,count(distinct student) as num
from Courses
group by class) as class
where num >=5
way2
# Write your MySQL query statement below
select
class
from Courses
group by class
having count(distinct student) >= 5
select
class
from Courses
group by class
having count(distinct student) >= 5
1729. 求关注者的数量
way1
# Write your MySQL query statement below
select
user_id
,count(distinct follower_id) as followers_count
from Followers
group by user_id
select
user_id
,count(distinct follower_id) as followers_count
from Followers
group by user_id
619. 只出现一次的最大数字
way1
# Write your MySQL query statement below
select
max(num) as num
from (select
num as num
from MyNumbers
group by num
having count(num) =1) a
select
max(num) as num
from (select
num as num
from MyNumbers
group by num
having count(num) =1) a
1045. 买下所有产品的客户
思路:因为product table的产品数目固定, 所以只要 groupby customer_id 后只要他们中
having count distinct product_key= product table的产品数目,
相当于购买了全部的产品
having count distinct product_key= product table的产品数目,
相当于购买了全部的产品
select
customer_id
from Customer c
group by customer_id
having count(distinct product_key) =
(select count(distinct product_key) from Product)
customer_id
from Customer c
group by customer_id
having count(distinct product_key) =
(select count(distinct product_key) from Product)
高级查询和连接
1731. 每位经理的下属员工数量
way1:自连接
select
t2.employee_id,
t2.name,
count(1) as reports_count,
round(avg(t1.age)) as average_age
from Employees t1, Employees t2
where t1.reports_to = t2.employee_id
group by 1
order by 1
t2.employee_id,
t2.name,
count(1) as reports_count,
round(avg(t1.age)) as average_age
from Employees t1, Employees t2
where t1.reports_to = t2.employee_id
group by 1
order by 1
1789. 员工的直属部门
way1:union all
# Write your MySQL query statement below
SELECT employee_id AS 'employee_id',
department_id AS 'department_id'
FROM Employee
WHERE primary_flag = 'Y'
UNION #联合查询,自动去重
SELECT employee_id AS 'employee_id',
department_id AS 'department_id'
FROM Employee
GROUP BY employee_id
HAVING COUNT(department_id) = 1
;
SELECT employee_id AS 'employee_id',
department_id AS 'department_id'
FROM Employee
WHERE primary_flag = 'Y'
UNION #联合查询,自动去重
SELECT employee_id AS 'employee_id',
department_id AS 'department_id'
FROM Employee
GROUP BY employee_id
HAVING COUNT(department_id) = 1
;
way2
# Write your MySQL query statement below
SELECT
employee_id
,IF(
COUNT(department_id)=1
,department_id
,MAX(
IF(primary_flag="Y",department_id,NULL)
)
) AS department_id
FROM
Employee
GROUP BY
employee_id
SELECT
employee_id
,IF(
COUNT(department_id)=1
,department_id
,MAX(
IF(primary_flag="Y",department_id,NULL)
)
) AS department_id
FROM
Employee
GROUP BY
employee_id
way3
/* Write your T-SQL query statement below */
select employee_id, department_id from
(
select
*,
count(*) over(partition by employee_id) as cnt
from Employee
) a
where primary_flag='Y' or cnt=1
select employee_id, department_id from
(
select
*,
count(*) over(partition by employee_id) as cnt
from Employee
) a
where primary_flag='Y' or cnt=1
way4
# Write your MySQL query statement below
select
employee_id,department_id
from Employee
where primary_flag ='Y'
or employee_id in (
select distinct employee_id from Employee
group by employee_id
having count(employee_id) = 1
)
select
employee_id,department_id
from Employee
where primary_flag ='Y'
or employee_id in (
select distinct employee_id from Employee
group by employee_id
having count(employee_id) = 1
)
# Write your MySQL query statement below
select
employee_id,department_id
from Employee
where primary_flag ='Y'
or employee_id not in (
select distinct employee_id from Employee
group by employee_id
having count(employee_id) >1
)
select
employee_id,department_id
from Employee
where primary_flag ='Y'
or employee_id not in (
select distinct employee_id from Employee
group by employee_id
having count(employee_id) >1
)
610. 判断三角形
way1
# Write your MySQL query statement below
select
x,y,z
,case when
x+y >z and x+z >y and y+z >x then 'Yes'
else 'No' end as triangle
from Triangle
select
x,y,z
,case when
x+y >z and x+z >y and y+z >x then 'Yes'
else 'No' end as triangle
from Triangle
select
x,y,z,if(x+y>z and x+z>y and y+z >x,'Yes','No') as triangle
from Triangle
x,y,z,if(x+y>z and x+z>y and y+z >x,'Yes','No') as triangle
from Triangle
180. 连续出现的数字
way1:自关联
# Write your MySQL query statement below
select
distinct a.Num ConsecutiveNums
from Logs a,Logs b,Logs c
where a.id = b.id -1 and b.id = c.id -1
and a.Num = b.Num and b.Num = c.Num
select
distinct a.Num ConsecutiveNums
from Logs a,Logs b,Logs c
where a.id = b.id -1 and b.id = c.id -1
and a.Num = b.Num and b.Num = c.Num
way2:考点:窗口函数lag, lead, row_number
select
distinct t.num as ConsecutiveNums
from
(
select
num,
lag(num, 1) over(order by id) as num1,
lag(num, 2) over(order by id) as num2
from Logs
) t
where t.num = t.num1 and t.num1 = t.num2
;
distinct t.num as ConsecutiveNums
from
(
select
num,
lag(num, 1) over(order by id) as num1,
lag(num, 2) over(order by id) as num2
from Logs
) t
where t.num = t.num1 and t.num1 = t.num2
;
select
distinct t.num as ConsecutiveNums
from
(
select
num,
lag(num, 1, null) over(order by id) as lag_num,
lead(num, 1, null) over(order by id) as lead_num
from Logs
) t
where t.num = t.lag_num and t.num = t.lead_num
;
distinct t.num as ConsecutiveNums
from
(
select
num,
lag(num, 1, null) over(order by id) as lag_num,
lead(num, 1, null) over(order by id) as lead_num
from Logs
) t
where t.num = t.lag_num and t.num = t.lead_num
;
select
distinct t.num as ConsecutiveNums
from
(
select
id,
num,
row_number() over(order by id) as rn,
row_number() over(partition by num order by id) as id_rn
from Logs
) t
group by t.num, (t.rn - t.id_rn)
having count(1) >= 3
;
distinct t.num as ConsecutiveNums
from
(
select
id,
num,
row_number() over(order by id) as rn,
row_number() over(partition by num order by id) as id_rn
from Logs
) t
group by t.num, (t.rn - t.id_rn)
having count(1) >= 3
;
1164. 指定日期的产品价格
way1:子查询
select p1.product_id, ifnull(p2.new_price, 10) as price
from (
select distinct product_id
from products
) as p1 -- 所有的产品
left join (
select product_id, new_price
from products
where (product_id, change_date) in (
select product_id, max(change_date)
from products
where change_date <= '2019-08-16'
group by product_id
)
) as p2 -- 在 2019-08-16 之前有过修改的产品和最新的价格
on p1.product_id = p2.product_id
from (
select distinct product_id
from products
) as p1 -- 所有的产品
left join (
select product_id, new_price
from products
where (product_id, change_date) in (
select product_id, max(change_date)
from products
where change_date <= '2019-08-16'
group by product_id
)
) as p2 -- 在 2019-08-16 之前有过修改的产品和最新的价格
on p1.product_id = p2.product_id
way2:union
分成2部分。把第一次change_date在2019-08-16之后的单独分出来,这部分的price肯定是10,因为初始值是10。
剩下的作为另外一部分,然后两部分做union。 另外一部分中,选出在2019-08-16之前最大的那天的price作为最终price就行了。
(select product_id as product_id,10 as price
from Products
group by product_id
having min(change_date)>'2019-08-16')
union
(select product_id,new_price as price
from Products
where (product_id,change_date) in
(select product_id,max(change_date) as max_date
from Products
where change_date<='2019-08-16'
group by product_id))
剩下的作为另外一部分,然后两部分做union。 另外一部分中,选出在2019-08-16之前最大的那天的price作为最终price就行了。
(select product_id as product_id,10 as price
from Products
group by product_id
having min(change_date)>'2019-08-16')
union
(select product_id,new_price as price
from Products
where (product_id,change_date) in
(select product_id,max(change_date) as max_date
from Products
where change_date<='2019-08-16'
group by product_id))
1204. 最后一个能进入电梯的人
way1:累加,开窗函数
# Write your MySQL query statement below
select
person_name
from (select
turn
,person_name
,sum(weight) over(order by turn) as total
from Queue) a where total <= 1000 order by turn desc limit 1
select
person_name
from (select
turn
,person_name
,sum(weight) over(order by turn) as total
from Queue) a where total <= 1000 order by turn desc limit 1
way2:自关联
SELECT a.person_name
FROM Queue a, Queue b
WHERE a.turn >= b.turn
GROUP BY a.person_id HAVING SUM(b.weight) <= 1000
ORDER BY a.turn DESC
LIMIT 1
FROM Queue a, Queue b
WHERE a.turn >= b.turn
GROUP BY a.person_id HAVING SUM(b.weight) <= 1000
ORDER BY a.turn DESC
LIMIT 1
1907. 按分类统计薪水
way1:数据缺失 、创建临时表,关联
with aa as (
SELECT 'Low Salary' as category
union all
SELECT 'Average Salary' as category
union all
SELECT 'High Salary' as category
),bb as (SELECT
case when income < 20000 then 'Low Salary'
when income >= 20000 and income <= 50000 then 'Average Salary'
when income > 50000 then 'High Salary'
end as category
,count(account_id) as accounts_count
from Accounts b
group by
case when income < 20000 then 'Low Salary'
when income >= 20000 and income <= 50000 then 'Average Salary'
when income > 50000 then 'High Salary'
end
)
select aa.category,ifnull(bb.accounts_count,0) as accounts_count from aa left join bb using(category)
SELECT 'Low Salary' as category
union all
SELECT 'Average Salary' as category
union all
SELECT 'High Salary' as category
),bb as (SELECT
case when income < 20000 then 'Low Salary'
when income >= 20000 and income <= 50000 then 'Average Salary'
when income > 50000 then 'High Salary'
end as category
,count(account_id) as accounts_count
from Accounts b
group by
case when income < 20000 then 'Low Salary'
when income >= 20000 and income <= 50000 then 'Average Salary'
when income > 50000 then 'High Salary'
end
)
select aa.category,ifnull(bb.accounts_count,0) as accounts_count from aa left join bb using(category)
## 拼接临时表
select
a.category
,ifnull(b.cnt,0) as accounts_count
from (select
'Low Salary' as category
union all
select
'Average Salary' as category
union all
select
'High Salary' as category) a left join (
select
case when income < 20000 then 'Low Salary'
when income > 50000 then 'High Salary'
else 'Average Salary'
end as category
,count(1) as cnt
from Accounts
group by case when income < 20000 then 'Low Salary'
when income > 50000 then 'High Salary'
else 'Average Salary'
end
) b
on a.category = b.category
select
a.category
,ifnull(b.cnt,0) as accounts_count
from (select
'Low Salary' as category
union all
select
'Average Salary' as category
union all
select
'High Salary' as category) a left join (
select
case when income < 20000 then 'Low Salary'
when income > 50000 then 'High Salary'
else 'Average Salary'
end as category
,count(1) as cnt
from Accounts
group by case when income < 20000 then 'Low Salary'
when income > 50000 then 'High Salary'
else 'Average Salary'
end
) b
on a.category = b.category
子查询
1978. 上级经理已离职的公司员工
# Write your MySQL query statement below
select
employee_id
from Employees
where manager_id not in (select distinct employee_id from Employees)
and salary < 30000
order by employee_id
select
employee_id
from Employees
where manager_id not in (select distinct employee_id from Employees)
and salary < 30000
order by employee_id
子主题
626. 换座位
SELECT
(CASE
WHEN MOD(id, 2) != 0 AND counts != id THEN id + 1
WHEN MOD(id, 2) != 0 AND counts = id THEN id
ELSE id - 1
END) AS id,
student
FROM
seat,
(SELECT
COUNT(*) AS counts
FROM
seat) AS seat_counts
ORDER BY id ASC;
(CASE
WHEN MOD(id, 2) != 0 AND counts != id THEN id + 1
WHEN MOD(id, 2) != 0 AND counts = id THEN id
ELSE id - 1
END) AS id,
student
FROM
seat,
(SELECT
COUNT(*) AS counts
FROM
seat) AS seat_counts
ORDER BY id ASC;
select
if(id%2=0,
id-1,
if(id=(select count(distinct id) from seat),
id,
id+1))
as id,student
from seat
order by id;
if(id%2=0,
id-1,
if(id=(select count(distinct id) from seat),
id,
id+1))
as id,student
from seat
order by id;
方法二:使用位操作和 COALESCE()【通过】
SELECT
s1.id, COALESCE(s2.student, s1.student) AS student
FROM
seat s1
LEFT JOIN
seat s2 ON ((s1.id + 1) ^ 1) - 1 = s2.id
ORDER BY s1.id;
s1.id, COALESCE(s2.student, s1.student) AS student
FROM
seat s1
LEFT JOIN
seat s2 ON ((s1.id + 1) ^ 1) - 1 = s2.id
ORDER BY s1.id;
1341. 电影评分
way1:union all
# 1.查找评论电影数量最多的用户名。如果出现平局,返回字典序较小的用户名。
select
a1.name as results
from ( select
u.name,count(user_id) as num
from MovieRating m left join Users u using(user_id)
group by u.name
order by count(user_id) desc,u.name asc limit 1) a1
union all
## 2.查找在 February 2020 平均评分最高 的电影名称。如果出现平局,返回字典序较小的电影名称
select
a2.title as results
from ( select
title,avg(rating) as avg_num
from MovieRating m left join Movies mo using(movie_id)
where date_format(created_at,'%Y-%m') = '2020-02'
group by title
order by avg(rating) desc,title asc limit 1) a2
select
a1.name as results
from ( select
u.name,count(user_id) as num
from MovieRating m left join Users u using(user_id)
group by u.name
order by count(user_id) desc,u.name asc limit 1) a1
union all
## 2.查找在 February 2020 平均评分最高 的电影名称。如果出现平局,返回字典序较小的电影名称
select
a2.title as results
from ( select
title,avg(rating) as avg_num
from MovieRating m left join Movies mo using(movie_id)
where date_format(created_at,'%Y-%m') = '2020-02'
group by title
order by avg(rating) desc,title asc limit 1) a2
## union all 拼接
select results from (select
name as results
from MovieRating left join Users using(user_id)
group by name
order by count(movie_id) desc,name limit 1) a
union all select results from (
select
title as results
from MovieRating left join Movies using(movie_id)
where year(created_at) = '2020' and month(created_at) = '02'
group by title
order by avg(rating) desc,title limit 1
) b
select results from (select
name as results
from MovieRating left join Users using(user_id)
group by name
order by count(movie_id) desc,name limit 1) a
union all select results from (
select
title as results
from MovieRating left join Movies using(movie_id)
where year(created_at) = '2020' and month(created_at) = '02'
group by title
order by avg(rating) desc,title limit 1
) b
1321. 餐馆营业额变化增长
way1:子查询
不使用窗口(自连接) 注意细节! ①取distinct(日期):小细节,因为一天有多次消费 ②自连接的条件:0<=datediff(被减数,减数)<=6 ;也可以这样写”between 0 and 6“ ③group by (distinct日期) ④求平均时不能使用avg!因为有的天有多笔消费
select
distinct a.visited_on,sum(b.amount) as amount,round(sum(b.amount)/7,2) as average_amount
from Customer a join Customer b
on datediff(a.visited_on,b.visited_on) between 0 and 6
group by a.visited_on,a.customer_id
having count(distinct b.visited_on) >=7
order by a.visited_on;
select
distinct a.visited_on,sum(b.amount) as amount,round(sum(b.amount)/7,2) as average_amount
from Customer a join Customer b
on datediff(a.visited_on,b.visited_on) between 0 and 6
group by a.visited_on,a.customer_id
having count(distinct b.visited_on) >=7
order by a.visited_on;
# Write your MySQL query statement below
SELECT
a.visited_on,
sum( b.amount ) AS amount,
round(sum( b.amount ) / 7, 2 ) AS average_amount
FROM
( SELECT DISTINCT visited_on FROM customer ) a JOIN customer b
ON datediff( a.visited_on, b.visited_on ) BETWEEN 0 AND 6
WHERE
a.visited_on >= (SELECT min( visited_on ) FROM customer ) + 6
GROUP BY
a.visited_on
SELECT
a.visited_on,
sum( b.amount ) AS amount,
round(sum( b.amount ) / 7, 2 ) AS average_amount
FROM
( SELECT DISTINCT visited_on FROM customer ) a JOIN customer b
ON datediff( a.visited_on, b.visited_on ) BETWEEN 0 AND 6
WHERE
a.visited_on >= (SELECT min( visited_on ) FROM customer ) + 6
GROUP BY
a.visited_on
way2:开窗函数、优秀的解法。
select
a2.visited_on,a2.amount,a2.average_amount
from (
select
visited_on
,row_number() over(order by visited_on) as rn
,sum(amount) over(order by visited_on rows 6 preceding) as amount
,round((avg(amount) over(order by visited_on rows 6 preceding) ),2) as average_amount
from (select
visited_on,sum(amount) as amount
from Customer
group by visited_on
order by visited_on) a1
) a2 where a2.rn >=7
a2.visited_on,a2.amount,a2.average_amount
from (
select
visited_on
,row_number() over(order by visited_on) as rn
,sum(amount) over(order by visited_on rows 6 preceding) as amount
,round((avg(amount) over(order by visited_on rows 6 preceding) ),2) as average_amount
from (select
visited_on,sum(amount) as amount
from Customer
group by visited_on
order by visited_on) a1
) a2 where a2.rn >=7
select
distinct a2.visited_on,a2.amount,a2.average_amount
from (
select
visited_on
,sum(amount) over(order by visited_on rows 6 preceding) as amount
,round((avg(amount) over(order by visited_on rows 6 preceding) ),2) as average_amount
from (select
visited_on,sum(amount) as amount
from Customer
group by visited_on
order by visited_on) a1
) a2 where datediff(a2.visited_on,(select min(visited_on) from Customer)) >= 6
distinct a2.visited_on,a2.amount,a2.average_amount
from (
select
visited_on
,sum(amount) over(order by visited_on rows 6 preceding) as amount
,round((avg(amount) over(order by visited_on rows 6 preceding) ),2) as average_amount
from (select
visited_on,sum(amount) as amount
from Customer
group by visited_on
order by visited_on) a1
) a2 where datediff(a2.visited_on,(select min(visited_on) from Customer)) >= 6
602. 好友申请 II :谁有最多的好友
成为朋友是一个双向的过程,所以如果一个人接受了另一个人的请求,他们两个都会多拥有一个朋友。
所以我们可以将 requester_id 和 accepter_id 联合起来,然后统计每个人出现的次数。
所以我们可以将 requester_id 和 accepter_id 联合起来,然后统计每个人出现的次数。
select
aa.id,count(aa.id) as num
from (select
requester_id as id
from RequestAccepted a
union all
select
accepter_id as id
from RequestAccepted b ) aa
group by id order by num desc limit 1
aa.id,count(aa.id) as num
from (select
requester_id as id
from RequestAccepted a
union all
select
accepter_id as id
from RequestAccepted b ) aa
group by id order by num desc limit 1
585. 2016年的投资
官方解法
## 1. 他在 2015 年的投保额 (TIV_2015) 至少跟一个其他投保人在 2015 年的投保额相同
select
round(sum(TIV_2016),2) as TIV_2016
from insurance where TIV_2015 in (select
TIV_2015
from insurance
group by TIV_2015
having count(TIV_2015) >1
)
and CONCAT(LAT, LON) in (
select
CONCAT(LAT, LON)
from insurance
group by LAT, LON
having count(*) = 1
)
select
round(sum(TIV_2016),2) as TIV_2016
from insurance where TIV_2015 in (select
TIV_2015
from insurance
group by TIV_2015
having count(TIV_2015) >1
)
and CONCAT(LAT, LON) in (
select
CONCAT(LAT, LON)
from insurance
group by LAT, LON
having count(*) = 1
)
select
round(sum(TIV_2016),2) as TIV_2016
from insurance where TIV_2015 in (
select
distinct TIV_2015
from insurance
group by TIV_2015 having count(TIV_2015) >1
)
and concat(',',LAT,LON) not in (
select
concat(',',LAT,LON)
from insurance
group by concat(',',LAT,LON)
having count(*) >1
)
round(sum(TIV_2016),2) as TIV_2016
from insurance where TIV_2015 in (
select
distinct TIV_2015
from insurance
group by TIV_2015 having count(TIV_2015) >1
)
and concat(',',LAT,LON) not in (
select
concat(',',LAT,LON)
from insurance
group by concat(',',LAT,LON)
having count(*) >1
)
185. 部门工资前三高的所有员工
way1
# Write your MySQL query statement below
select
d.name as 'Department',e1.name as Employee,e1.salary as Salary
from Employee e1
join Department d on e1.departmentId = d.id
where 3 > (
select
count(distinct e2.salary)
from Employee e2
where e2.salary > e1.salary
and e1.departmentId = e2.DepartmentId
)
select
d.name as 'Department',e1.name as Employee,e1.salary as Salary
from Employee e1
join Department d on e1.departmentId = d.id
where 3 > (
select
count(distinct e2.salary)
from Employee e2
where e2.salary > e1.salary
and e1.departmentId = e2.DepartmentId
)
way2
# Write your MySQL query statement below
select
a.name as Department,a.Employee,a.Salary
from (select
d.name
,e.name as Employee
,e.salary as Salary
,dense_rank() over(partition by e.departmentId order by e.salary desc ) as rn
from Employee e left join Department d on e.departmentId = d.id
group by e.id,e.name,e.salary) a where a.rn <= 3;
select
a.name as Department,a.Employee,a.Salary
from (select
d.name
,e.name as Employee
,e.salary as Salary
,dense_rank() over(partition by e.departmentId order by e.salary desc ) as rn
from Employee e left join Department d on e.departmentId = d.id
group by e.id,e.name,e.salary) a where a.rn <= 3;
高级字符串函数 / 正则表达式 / 子句
1667. 修复表中的名字
way1
# Write your MySQL query statement below
select user_id,
CONCAT(Upper(left(name,1)),Lower(substring(name,2))) name
from users
order by user_id
select user_id,
CONCAT(Upper(left(name,1)),Lower(substring(name,2))) name
from users
order by user_id
1527. 患某种疾病的患者
way1
# Write your MySQL query statement below
select
*
from Patients
where conditions like '% DIAB1%' or conditions like 'DIAB1%'
select
*
from Patients
where conditions like '% DIAB1%' or conditions like 'DIAB1%'
way2
# Write your MySQL query statement below
SELECT
*
FROM
PATIENTS
WHERE
CONDITIONS REGEXP '^DIAB1|\\sDIAB1';
SELECT
*
FROM
PATIENTS
WHERE
CONDITIONS REGEXP '^DIAB1|\\sDIAB1';
196. 删除重复的电子邮箱
way1:not in
DELETE FROM Person
WHERE id NOT IN(
SELECT
id
FROM (
SELECT
MIN(id) as id
FROM Person
Group by email
)t
)
WHERE id NOT IN(
SELECT
id
FROM (
SELECT
MIN(id) as id
FROM Person
Group by email
)t
)
way2:自关联
DELETE p1 FROM Person p1,
Person p2
WHERE
p1.Email = p2.Email AND p1.Id > p2.Id
Person p2
WHERE
p1.Email = p2.Email AND p1.Id > p2.Id
176. 第二高的薪水
way1
SELECT
IFNULL(
(SELECT DISTINCT Salary
FROM Employee
ORDER BY Salary DESC
LIMIT 1 OFFSET 1),
NULL) AS SecondHighestSalary
IFNULL(
(SELECT DISTINCT Salary
FROM Employee
ORDER BY Salary DESC
LIMIT 1 OFFSET 1),
NULL) AS SecondHighestSalary
way2:子查询
# Write your MySQL query statement below
select
max(salary) as SecondHighestSalary
from Employee where salary < (select
max(salary) as salary
from Employee)
select
max(salary) as SecondHighestSalary
from Employee where salary < (select
max(salary) as salary
from Employee)
way3:开窗+rank
select(
select
salary
from (
select
distinct(salary),
rank() over(order by salary desc) rk
from Employee
) a where rk = 2
) as SecondHighestSalary
select
salary
from (
select
distinct(salary),
rank() over(order by salary desc) rk
from Employee
) a where rk = 2
) as SecondHighestSalary
1484. 按日期分组销售产品
way1:gruop_concat
select
sell_date,count(distinct product) as num_sold
,group_concat(
distinct product
order by product separator ','
) products
from Activities
group by sell_date
order by sell_date
sell_date,count(distinct product) as num_sold
,group_concat(
distinct product
order by product separator ','
) products
from Activities
group by sell_date
order by sell_date
1327. 列出指定时间段内所有的下单产品
way1:with as
# Write your MySQL query statement below
with aa as(
select
product_id,sum(unit) as units
from Orders
where date_format(order_date,'%Y-%m') = '2020-02'
group by product_id
having units >=100
)
select
bb.product_name
,aa.units as unit
from aa left join Products bb using(product_id)
with aa as(
select
product_id,sum(unit) as units
from Orders
where date_format(order_date,'%Y-%m') = '2020-02'
group by product_id
having units >=100
)
select
bb.product_name
,aa.units as unit
from aa left join Products bb using(product_id)
way2:
select
product_name,
sum(unit) unit
from Orders O
left join Products P using(product_id)
where order_date like '2020-02%'
group by product_name
having unit >= 100
product_name,
sum(unit) unit
from Orders O
left join Products P using(product_id)
where order_date like '2020-02%'
group by product_name
having unit >= 100
1517. 查找拥有有效邮箱的用户
way1:正则
# Write your MySQL query statement below
SELECT
user_id AS 'user_id',
name AS 'name',
mail AS 'mail'
FROM
Users
WHERE mail regexp '^[a-zA-Z][a-zA-Z0-9/\\_\\.\\-]*@leetcode\\.com'
;
# Write your MySQL query statement below
SELECT
user_id AS 'user_id',
name AS 'name',
mail AS 'mail'
FROM
Users
WHERE mail regexp '^[a-zA-Z][a-zA-Z0-9/\\_\\.\\-]*@leetcode\\.com'
;
题型
简单: 33 道
中等: 16 道
困难: 1 道
谓词下推
面试 on 和 where 区别
需要二刷、多刷复习的题目
0 条评论
下一页