刷完了简单和中等难度的数据库题目,对sql中的一些语法特性有了简单的了解,算是学会了挺多思路,还有很多的小技巧
总之就是感觉使用sql能完成的任务越来越多了,能解决的业务场景也也越来越复杂了。有许多之前不得不拿到程序中才能处理的数据使用简单的sql就能够达成,当事人就很有成就感。
所以刷题整理这个过程还会持续下去,从这篇博文开始,就是中等难度的了,由于题目较长或者题解较简单稍微复杂。所以为了避免每篇博文过于冗长,暂定是5-6道题一篇。会挑选博主觉得比较有意义的题目(根据博主不算高的水平)
往期的题解会放在最后,欢迎阅览、交流、讨论。
题目链接
这道题,先去记录中查询出所有被举报的条目,然后让这些记录和被移除的表单进行联结(注意使用内连接,方便统计),
接着按照日期分组,使用聚合函数配合case语句计算出每一天的比率。
那么最后再对所有日期的比率计算平均值,转化成百分数,保留两位小数输出即可
# Write your MySQL query statement below
select
round(avg(rate) * 100,2) average_daily_percent
from
(
select
action_date,
sum(case when r.remove_date is null then 0 else 1 end)/count(a.post_id) rate
from
(
select
distinct post_id,
action_date
from
actions
where
action = 'report'
and
extra = 'spam'
) a
left join removals r on r.post_id = a.post_id
group by
action_date
)t
;
题目链接
这个题,需要我们统计在某日期时所有商品的价格。这道题的难点在于,商品价格取决于最后一次改变定价的价格,其中还存在价格没有改变过的情况。
解决这个问题的子问题,就是要找出每个商品在该日期前的最新一次的价格修改日期,进而获得最新价格。
我们可以先使用where子句筛选出所有在该日期前的记录,并将这些记录按照商品分组,使用聚合函数来获得每个商品最后更改的日期。
但是这样的查询只能查询出每个商品对应的最新修改日期,并不能获得该日期的价格,所以我们还需要在外面再写一层查询,查询出每个商品对应日期的价格(这里可以使用where子句中的in条件的多关键字判定)
此时这张表中的每条记录就是每个商品最新的价格了。
但是!!!!
还有一个关键的问题,那就是当前所有查询出来的商品及其价格都是发生过修改的价格,那些没有发生过任何修改的商品是不在当前表单中的。为了补上这个缺口,还需要再添加一层查询,这一层可以是在查询中筛选,也可以使用联结,总之就是补上所有没有修改过价格的商品即可。
# Write your MySQL query statement below
select
ids.product_id,
(case when prices.new_price is null then 10 else prices.new_price end) as price
from
(
select
distinct product_id
from
products
) ids
left join(
select
product_id,
new_price
from
products
where
(product_id,change_date) in (
select
product_id,
max(change_date) as change_date
from
products
where
change_date <= '2019-08-16'
group by
product_id
)
) prices on ids.product_id = prices.product_id
;
题目链接
这道题需要我们查询出每个用户的注册日期和2019年的订单数量。
简单分析一下不难发现,这个题的两个需求没有必然联系。
于是我们可以分开查询最后再联结到一起。
对于注册时间,这个信息已经在用户表单中存在了,所以任务只剩下了一件,就是查询出每个用户在2019年的订单数并将它们联结到用户表上。
统计订单数量是个简单的问题,先用where将所有2019年的订单筛选出来,接着按照用户进行分组,再分别使用聚合函数统计即可。
最后!!!记得处理没有订单的情况,使用ifnull来单独处理那些null值,将它们变成0输出
# Write your MySQL query statement below
select
user_id as buyer_id ,
join_date,
ifnull(item_brand,0) as 'orders_in_2019'
from
users
left join(
select
buyer_id,
count(order_id) as item_brand
from
orders
where
year(order_date) = 2019
group by
buyer_id
)o on o.buyer_id = users.user_id
;
题目链接
这道题需要我们统计所有用户的首次订单中即时订单的占比,即时订单的定义就是下单的日期与需求的日期是同一天。
首先可以先查出所有用户的首订单,按照用户分组,取最小的订单日期即可。
获得所有用户的首订单之后呢,就需要对所有首订单进行筛选。这个筛选需要再写一层查询,因为刚才的查询只能确定首订单的订单日期并不能获得其接收日期。
在外层查询中,可以使用where语句的in条件筛选出所有的首订单,接着使用聚合函数和case筛选出所有的即时订单(具体的就是比较订单日期和接受日期是否相同),其中的case也可以使用if来完成。
# Write your MySQL query statement below
select
round(sum(case when order_date = customer_pref_delivery_date then 1 else 0 end) / count(customer_id) * 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
)
题目链接
这道题需要我们统计每个国家或地区的事务数及其总金额以及批准的事务数及其总金额。
其实这道题在实现上没什么绕弯的地方,收录它的原因在于这道题充分发挥聚合函数配合分支语句的筛选功能。
# Write your MySQL query statement below
select
left(trans_date,7) as 'month',
country,
count(id) as trans_count,
sum(case when state = 'approved' then 1 else 0 end) as approved_count,
sum(amount) as trans_total_amount,
sum(case when state = 'approved' then amount else 0 end) as approved_total_amount
from
transactions
group by
concat(year(trans_date),month(trans_date)),country