MySQL高频题刷题笔记

  1. 1. 1683.无效的推文–计算列中字符串的字符数
  2. 2. 197. 上升的温度–日期算数函数
  3. 3. 1661. 每台机器的进程平均运行时间
  4. 4. 1280. 学生们参加各科测试的次数
  5. 5. 570. 至少有5名直接下属的经理
  6. 6. 1251. 平均售价–将null替换为实际值
  7. 7. 1633. 各赛事的用户注册率
  8. 8. 1193. 每月交易 I –日期格式转换
  9. 9. 1174. 即时食物配送 II
  10. 10. 550. 游戏玩法分析 IV
  11. 11. 619. 只出现一次的最大数字
  12. 12. 1045. 买下所有产品的客户

1683.无效的推文–计算列中字符串的字符数

CHAR_LENGTH() 或 LENGTH() 函数来计算列中字符串的字符数。
这两个函数的区别在于处理非 ASCII 字符时的行为:
CHAR_LENGTH() 返回字符串的字符数,而 LENGTH() 返回字符串的字节数。
对于 ASCII 字符,这两个函数的结果是相同的。

197. 上升的温度–日期算数函数

  • DATEDIFF(startdate , enddate) 函数计算两个日期间的差
    datediff(日期1,日期2)
    返回日期1与日期2相差的天数。
    如果日期1比日期2大,结果为正;如果小,结果为负。

  • DATEADD(datepart,number,date) 函数计算一个日期通过给时间间隔加减来获得一个新日期
    number添加的间隔数;对于未来的时间,是正数,对于过去的时间,是负数。
    date合法的日期表达式。
    dateadd(单位,添加的时间间隔数,日期)获得一个新日期

  • DATE_ADD(date,INTERVAL expr type) 函数执行日期的加运算
    date: 日期,expr: 添加的时间间隔数值,type: 时间单位
    date_add(日期,interval 时间数值 时间单位)

1661. 每台机器的进程平均运行时间

  • if(条件,true,false) 函数
    true对应1false对应0时,可简略为(条件)这个等价布尔表达式
  • round(para,n) para保留n位小数,n 省略时即取整
1
2
3
4
select machine_id,
round(2*avg(if(activity_type = 'start',-1,1)*timestamp),3) as processing_time
from Activity
group by machine_id;

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

笛卡尔积 cross join

1
2
3
4
5
6
select t.student_id, student_name, t.subject_name, count(e.subject_name) as attended_exams
from (select * from Students cross join Subjects ) t
left join Examinations e
on e.student_id = t.student_id and e.subject_name = t.subject_name
group by t.student_id, student_name, t.subject_name
order by t.student_id, t.subject_name;

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

聚合函数(如 count ())不能直接用在 where 子句中。
where 子句用于筛选原始行数据,而聚合函数是对分组后的数据进行计算,筛选分组结果需要用 having 子句。

1
2
3
4
5
6
select e1.name
from Employee e1
join Employee e2
on e1.id = e2.managerId
group by e1.id
having count(*) >= 5;

count(e2.name) 建议改为 count(*),避免因 e2.name 为 null 导致计数不准。

1251. 平均售价–将null替换为实际值

ifnull(para,n):如果 para 是 null ,将 para 替换为 n
判断日期区间可用between… and…

1
2
3
4
5
6
select p.product_id,
round(ifnull(sum(p.price * u.units) / sum(u.units), 0), 2) as average_price
from Prices p
left join UnitsSold u
on p.product_id = u.product_id and purchase_date between start_date and end_date
group by p.product_id;

1633. 各赛事的用户注册率

1
2
3
4
select contest_id, round(count(user_id)/(select count(*) from Users)* 100, 2) as percentage
from Register r
group by contest_id
order by percentage desc, contest_id;

1193. 每月交易 I –日期格式转换

data_format(date, ‘%Y-%m’) 将data转为年-月格式
if(state = ‘approved’, 1, 0) –> state = ‘approved’
布尔表达式,简化更快

1
2
3
4
5
6
7
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', 1, 0) * amount) as approved_total_amount
from Transactions
group by month, country;

1174. 即时食物配送 II

if(order_date = customer_pref_delivery_date, 1, 0) –> order_date = customer_pref_delivery_date
布尔表达式,简化更快

1
2
3
4
5
6
select 
round(avg(if(order_date = customer_pref_delivery_date, 1, 0)) * 100, 2)
as immediate_percentage
from Delivery
where (customer_id, order_date) in
(select customer_id, min(order_date) from Delivery group by customer_id); #找出首次订单

550. 游戏玩法分析 IV

1
2
3
4
5
6
7
8
select 
round(avg(event_date is not null), 2) as fraction
from
(select player_id, min(event_date) as first_login
from Activity
group by player_id) fl #首次登录
left join Activity a
on fl.player_id = a.player_id and datediff(a.event_date, fl.first_login) = 1;

619. 只出现一次的最大数字

1
2
3
4
5
6
7
8
select
(select num
from MyNumbers
group by num
having count(num) = 1
order by num desc
limit 1)
as num;

1045. 买下所有产品的客户

1
2
3
4
5
select customer_id
from customer
group by customer_id
having count(distinct(product_key)) =
(select count(product_key) from product);