主题
高频 SQL 50 题(基础版) 已完结
查询
可回收且低脂的产品
sql
select product_id from Products where low_fats = "Y" and recyclable = "Y";
寻找用户推荐人
提示
NULL 值判断需要使用 is null
或 is not null
。
sql
select name from Customer where referee_id is null or referee_id != 2;
大的国家
sql
select name,population,`area` from World
where `area` >= 3000000 or population >= 25000000;
文章浏览 I
提示
去重:distinct [name]
排序:order by [name]
sql
select distinct author_id id
from Views where author_id = viewer_id
order by id;
无效的推文
提示
获取字符串长度(ASCII):length()
获取字符串长度(更多字符):char_length()
sql
select tweet_id from Tweets
where length(content) > 15;
连接
使用唯一标识码替换员工ID
提示
保留 NULL 使用外连接,不保留 NULL 使用内连接。
使用 on
作为外连接的条件。
sql
select unique_id, name
from Employees left join EmployeeUNI
on Employees.id = EmployeeUNI.id;
产品销售分析 I
多表查询
sql
select product_name, `year`, price
from Sales, Product
where Sales.product_id = Product.product_id;
进店却未进行过交易的顾客
sql
select customer_id, count(*) count_no_trans
from Visits
left join Transactions
on Transactions.visit_id = Visits.visit_id
where transaction_id is null
group by customer_id;
上升的温度
提示
比较日期数据:datediff(date1, date2)
sql
select w1.id
from Weather w1 join Weather w2
on datediff(w1.recordDate , w2.recordDate) = 1
where w1.temperature > w2.temperature;
每台机器的进程平均运行时间
sql
select machine_id, round(avg(processing_time), 3) processing_time
from (
select a1.machine_id, a1.process_id, a2.timestamp - a1.timestamp processing_time
from (select * from Activity where activity_type = "start") a1
join (select * from Activity where activity_type = "end") a2
on a1.machine_id = a2.machine_id and a1.process_id = a2.process_id
) t
group by machine_id;
员工奖金
sql
select name, bonus
from Employee e
left join Bonus b
on b.empId = e.empId
where bonus is null or bonus < 1000;
学生们参加各科测试的次数
提示
交叉联接(笛卡尔积):cross join
对 NULL 值处理:ifnull([name], [defult_value])
sql
select
student_id, e.student_name, s.subject_name,
ifnull(sum(e.subject_name = s.subject_name), 0) attended_exams
from (
select ss.student_id, ss.student_name, ee.subject_name
from Students ss
left join Examinations ee
on ee.student_id = ss.student_id
) e
cross join Subjects s
group by student_id, s.subject_name
order by student_id, s.subject_name;
至少有5名直接下属的经理
sql
select e.name
from (
select managerId, count(*) cnt
from Employee
group by managerId
) t
join Employee e
on e.id = t.managerId
where t.managerId is not null and t.cnt >= 5;
确认率
sql
select
c.user_id,
ifnull(round(sum(c.action = "confirmed") * 1. / count(*), 2), 0) confirmation_rate
from (
select s.user_id, c.action
from Confirmations c
right join Signups s
on c.user_id = s.user_id
) c
group by c.user_id;
聚合函数
有趣的电影
sql
select *
from cinema
where description != "boring" && id % 2 = 1
order by rating desc;
平均售价
sql
select t.product_id, ifnull(round(sum(t.total) * 1. / sum(units), 2), 0) average_price
from (
select p.product_id, units , units * price total
from UnitsSold u
right join Prices p
on u.product_id = p.product_id and datediff(u.purchase_date, p.start_date) >= 0 and datediff(u.purchase_date, p.end_date) <= 0
) t
group by t.product_id;
项目员工 I
sql
select p.project_id ,round(avg(experience_years), 2) as average_years
from Project p
left join Employee e
on p.employee_id = e.employee_id
group by project_id
各赛事的用户注册率
sql
select
contest_id,
round(count(*) * 100. / (select count(*) from Users), 2) percentage
from Register r
group by contest_id
order by percentage desc, contest_id;
查询结果的质量和占比
sql
select
t.query_name,
round(avg(t.quality), 2) quality,
round(sum(t.rating < 3) * 100. / count(*), 2) poor_query_percentage
from (
select *, rating / position quality
from Queries
) t
where query_name is not null
group by t.query_name;
排序和分组
每位教师所教授的科目种类的数量
去重
sql
select t.teacher_id, count(distinct subject_id) cnt
from Teacher t
group by t.teacher_id;
分组聚合
sql
select t.teacher_id, count(*) cnt
from (
select teacher_id, subject_id
from Teacher
group by teacher_id, subject_id
) t
group by t.teacher_id;
查询近30天活跃用户数
sql
select activity_date `day`, count(distinct user_id) active_users
from Activity
where
datediff("2019-07-27", activity_date) < 30 && datediff("2019-07-27", activity_date) >= 0
group by activity_date;
销售分析III
sql
select p.product_id, p.product_name
from (
select p.*
from Product p
join Sales s
where p.product_id = s.product_id
group by product_id
) p
left join (
select distinct product_id, sale_date
from Sales
where
datediff("2019-01-01", sale_date) > 0
or datediff(sale_date, "2019-03-31") > 0
) t
on p.product_id = t.product_id
where t.sale_date is null;
超过 5 名学生的课
sql
select class
from (
select class, count(*) cnt
from Courses
group by class
) t
where t.cnt >= 5;
求关注者的数量
sql
select user_id, count(*) followers_count
from Followers
group by user_id
order by user_id;
只出现一次的最大数字
提示
聚合函数过滤使用 having
。
sql
select max(t.num) num
from (
select *, count(*) cnt
from MyNumbers
group by num
having cnt = 1
order by cnt, num desc
) t;
买下所有产品的客户
sql
select customer_id
from Customer
group by customer_id
having count(distinct product_key) = (select count(*) from Product);
每月交易 I
提示
日期格式化,将年月日格式化成年月:date_format(trans_date, '%Y-%m')
if 函数:if(条件, true返回值, false 返回值)
sql
select
date_format(trans_date, '%Y-%m') month,
country,
count(*) trans_count,
sum(state = "approved") approved_count,
sum(amount) trans_total_amount,
sum(if(state = "approved", amount, 0)) approved_total_amount
from Transactions
group by country, month;
即时食物配送 II
sql
select
round(sum(t.min_date = t.customer_pref_delivery_date) * 100. / count(distinct t.customer_id), 2) immediate_percentage
from(
select
customer_id , min(order_date) min_date,
min(customer_pref_delivery_date) customer_pref_delivery_date
from Delivery
where datediff(order_date, customer_pref_delivery_date) <= 0
group by customer_id
) t
游戏玩法分析 IV
sql
select
round(
sum(event_date is not null) * 1. / count(t.player_id),
2
) fraction
from (
select player_id, min(event_date) date
from Activity
group by player_id
) t
left join Activity a
on
datediff(a.event_date, t.date) = 1
and a.player_id = t.player_id
高级查询和连接
每位经理的下属员工数量
sql
select e2.employee_id, e2.name, count(*) reports_count, round(avg(e1.age), 0) average_age
from Employees e1
left join Employees e2
on e1.reports_to = e2.employee_id
where e2.employee_id is not null
group by e2.employee_id
order by employee_id
员工的直属部门
sql
select
e1.employee_id,
ifnull(e2.department_id, e1.department_id) department_id
from (
select * from Employee group by employee_id
) e1
left join (
select *
from Employee
where primary_flag = "Y"
) e2
on e1.employee_id = e2.employee_id
判断三角形
sql
select
*,
if((x + y > z) and (x + z > y) and (y + z > x), "Yes", "No") triangle
from Triangle;
连续出现的数字
sql
select distinct l1.num ConsecutiveNums
from Logs l1, Logs l2, Logs l3
where
l1.id = l2.id - 1
and l2.id = l3.id - 1
and l1.num = l2.num
and l2.num = l3.num
指定日期的产品价格
sql
select distinct p.product_id, if(t.product_id is null, 10, p.new_price) price
from Products p
left join(
select product_id, max(change_date) max_date
from Products
where datediff("2019-08-16", change_date) >= 0
group by product_id
) t
on p.product_id is null or t.product_id = p.product_id
where t.max_date is null or t.max_date = p.change_date
order by price desc;
最后一个能进入巴士的人
提示
使用变量:创建临时表创建变量,使用 @k := v
赋值
sql
select t.person_name
from (
select person_name, @sum := @sum + weight weight
from Queue , (select @sum := 0) tmp
order by turn
) t
where weight <= 1000
order by weight desc
limit 1
按分类统计薪水
提示
使用 union
可以将多个单独查询的结果组合在一起。
union all
不会去重,union
会去重
sql
select 'Low Salary' category, sum(income < 20000) accounts_count
from Accounts
union
select 'Average Salary' category, sum(income <= 50000 and income >= 20000) accounts_count
from Accounts
union
select 'High Salary' category, sum(income > 50000) accounts_count
from Accounts
子查询
上级经理已离职的公司员工
sql
select t.employee_id
from (
select e1.employee_id, e2.name manager_name, e1.salary
from (
select * from Employees e where manager_id is not null
) e1
left join Employees e2
on e1.manager_id = e2.employee_id
) t
where t.salary < 30000 and t.manager_name is null
order by employee_id;
换座位
sql
select *
from ((
select ifnull(s2.id, s1.id) id, s1.student
from Seat s1
left join Seat s2
on s2.id = s1.id + 1
where s1.id % 2 = 1
) union (
select ifnull(s2.id, s1.id) id, s1.student
from Seat s1
left join Seat s2
on s2.id = s1.id - 1
where s1.id % 2 = 0
)) t
order by t.id
电影评分
sql
(
select name results
from MovieRating mr
join Users u
on u.user_id = mr.user_id
group by mr.user_id
order by count(*) desc, u.name
limit 1
)
union all
(
select title results
from (
select mr.movie_id, avg(mr.rating) avg_rating
from MovieRating mr
where date_format(mr.created_at, "%Y-%m") = "2020-02"
group by mr.movie_id
) t
left join Movies m
on m.movie_id = t.movie_id
order by avg_rating desc, title
limit 1
)
餐馆营业额变化增长
sql
with Cust as (
select visited_on, sum(amount) amount
from Customer
group by visited_on
)
select
c.visited_on visited_on,
sum(c1.amount) amount,
round(sum(c1.amount) * 1. / 7 ,2) average_amount
from Cust c
cross join Cust c1
on datediff(c.visited_on, c1.visited_on) >= 0 and datediff(c.visited_on, c1.visited_on) < 7
group by c.visited_on
having count(*) = 7
好友申请 II :谁有最多的好友
sql
select id, count(id) num
from(
select requester_id id
from RequestAccepted
union all
select accepter_id id
from RequestAccepted
) t
group by id
order by num desc
limit 1
2016年的投资
sql
select
round(sum(tiv_2016), 2) tiv_2016
from Insurance i
where
i.tiv_2015 in (select i1.tiv_2015 from Insurance i1 where i.pid != i1.pid)
and concat(i.lat,',',i.lon) in (select concat(lat,',',lon) from Insurance group by lat,lon having count(*) < 2)
部门工资前三高的所有员工
sql
select
d.name Department,
e.name Employee,
e.salary Salary
from Employee e
left join Department d
on e.departmentId = d.id
where
(
select count(distinct e1.salary)
from Employee e1
where e.departmentId = e1.departmentId and e1.salary > e.salary
) < 3
高级字符串函数 / 正则表达式 / 子句
修复表中的名字
提示
- 字符串连接:
concat(str1, str2)
- 大小写转换:
upper(str)
、lower(str)
- 从左边或右边截取子串:
left(str, n)
、right(str, n)
- 获取字符串长度:
length(str)
sql
select
user_id,
concat(upper(left(name, 1)), lower(right(name, length(name) - 1))) name
from Users
order by user_id;
患某种疾病的患者
sql
select *
from Patients
where conditions like 'DIAB1%' or conditions like '% DIAB1%';
删除重复的电子邮箱
where
不能直接引用包含聚合函数的列,需要中间表。
sql
delete
from Person
where id not in (
select * from (
select min(id) from Person group by email
) t
)
第二高的薪水
sql
select max(salary) SecondHighestSalary
from Employee
where salary != (
select max(salary) from Employee
);
按日期分组销售产品
提示
字符串拼接函数
sql
group_concat(
[distinct] 字段
[order by 排序字段]
[separator '分隔符']
)
sql
select
sell_date,
count(distinct product) num_sold,
group_concat(
distinct product
order by product
separator ','
) products
from Activities
group by sell_date
order by sell_date
列出指定时间段内所有的下单产品
sql
select product_name , sum(unit) unit
from Orders o, Products p
where
date_format(o.order_date, "%Y-%m") = "2020-02"
and o.product_id = p.product_id
group by o.product_id
having unit >= 100
查找拥有有效邮箱的用户
正则表达式
^
:表示字符串的开始。$
:表示字符串的结束。\w
:字符集
sql
select *
from Users
where mail regexp '^[a-zA-Z][\\w.-]*\\@leetcode\\.com$'