题目:
1)请统计国庆头3天里,每天的近7日 日均订单完成量和日均订单取消量,保留2位小数
2)结果按日期升序排序
考察知识点:
1)窗口函数中的 移动平均计算
题解:有“拆解版”,和“一步到位版”
【拆解版】
步骤1:找出每天的订单完成量和订单取消量
SELECT DATE(order_time) AS dt, /* 转化成日期 */
COUNT(mileage) AS finish, /* 完成量 */
COUNT(CASE WHEN mileage IS NULL THEN 1 ELSE NULL END) AS cancel
/* 取消量:当mileage为空时,则代表该订单是未发生的、被取消的 */
FROM tb_get_car_order
GROUP BY DATE(order_time)
步骤2:找出每天的“近7天的日均完成量和取消量”,这里则需要用到移动平均窗口
基于步骤1的查询结果,对其再嵌套一层查询,得出日均完成量和取消量
SELECT dt,
AVG(finish) OVER (ORDER BY dt ASC ROWS 6 PRECEDING) AS finish_num_7d,
/* 近7天的日均完成量 */
AVG(cancel) OVER (ORDER BY dt ASC ROWS 6 PRECEDING) AS cancel_num_7d
/* 近7天的日均取消量 */
FROM
/* 步骤1的查询结果 */
(SELECT DATE(order_time) AS dt,
COUNT(mileage) AS finish,
COUNT(CASE WHEN mileage IS NULL THEN 1 ELSE NULL END) AS cancel
FROM tb_get_car_order
GROUP BY DATE(order_time)) AS t1
步骤3:最后,从步骤2的结果中,筛选出国庆头3天的数据即可
很简单了,WHERE子句来筛选,ROUND函数对计算量进行四舍五入,并按照日期升序排序即可
SELECT dt,
ROUND(finish_num_7d, 2) AS finish_num_7d,
ROUND(cancel_num_7d, 2) AS cancel_num_7d
FROM
/* 步骤2的查询结果 */
(SELECT dt,
AVG(finish) OVER (ORDER BY dt ASC ROWS 6 PRECEDING) AS finish_num_7d,
AVG(cancel) OVER (ORDER BY dt ASC ROWS 6 PRECEDING) AS cancel_num_7d
FROM
/* 步骤1的查询结果 */
(SELECT DATE(order_time) AS dt,
COUNT(mileage) AS finish,
COUNT(CASE WHEN mileage IS NULL THEN 1 ELSE NULL END) AS cancel
FROM tb_get_car_order
GROUP BY DATE(order_time)) AS t1) AS t2
WHERE dt BETWEEN '2021-10-01' AND '2021-10-03'
ORDER BY dt ASC;
【一步到位版】
从上述步骤2可知,关键一步在于对步骤1的GROUP BY结果后进行计算移动平均的窗口操作,这一步其实可以直接合并到步骤1当中
# 步骤2中的AVG(finish),其实就是AVG(COUNT(mileage)):
AVG( COUNT(mileage) ) OVER (ORDER BY DATE(order_time) ASC ROWS 6 PRECEDING)
# 同理,AVG(cancel)则是:
AVG( COUNT(CASE WHEN mileage IS NULL THEN 1 ELSE NULL END) ) OVER (ORDER BY DATE(order_time) ASC ROWS 6 PRECEDING)
因此,可得出查询语句:
SELECT DATE(order_time) AS dt,
COUNT(mileage) AS finish, /* 每天的完成量 */
COUNT(CASE WHEN mileage IS NULL THEN 1 ELSE NULL END) AS cancel, /* 每天的取消量 */
ROUND(AVG(COUNT(mileage)) OVER (ORDER BY DATE(order_time) ASC ROWS 6 PRECEDING), 2) AS finish_num_7d,
/* 每天的近7天日均完成量,并且直接保留2位小数 */
ROUND(AVG(COUNT(CASE WHEN mileage IS NULL THEN 1 ELSE NULL END)) OVER (ORDER BY DATE(order_time) ASC ROWS 6 PRECEDING), 2) AS cancel_num_7d
/* 每天的近7天日均取消量,并且直接保留2位小数 */
FROM tb_get_car_order
GROUP BY DATE(order_time)
最后,再嵌套一层子查询,筛选出国庆头3天即可(好像也不是一步到位啊我靠):
SELECT dt, finish_num_7d, cancel_num_7d
FROM
(SELECT DATE(order_time) AS dt,
COUNT(mileage) AS finish,
COUNT(CASE WHEN mileage IS NULL THEN 1 ELSE NULL END) AS cancel,
ROUND(AVG(COUNT(mileage)) OVER (ORDER BY DATE(order_time) ASC ROWS 6 PRECEDING), 2) AS finish_num_7d,
ROUND(AVG(COUNT(CASE WHEN mileage IS NULL THEN 1 ELSE NULL END)) OVER (ORDER BY DATE(order_time) ASC ROWS 6 PRECEDING), 2) AS cancel_num_7d
FROM tb_get_car_order
GROUP BY DATE(order_time)) AS t1
WHERE dt BETWEEN '2021-10-01' AND '2021-10-03'
ORDER BY dt ASC