首页 > 试题广场 >

国庆期间近7日日均取消订单量

[编程题]国庆期间近7日日均取消订单量
  • 热度指数:24191 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解

现有用户打车记录表tb_get_car_record

id uid city event_time end_time order_id
1 101 北京 2021-09-25 08:28:10 2021-09-25 08:30:00
9011
2 102 北京
2021-09-25 09:00:30
2021-09-25 09:01:00
9012
3 103 北京
2021-09-26 07:59:00 2021-09-26 08:01:00
9013
4 104 北京
2021-09-26 07:59:00 2021-09-26 08:01:00
9023
5 104 北京
2021-09-27 07:59:20 2021-09-27 08:01:00
9014
6 105 北京
2021-09-28 08:00:00 2021-09-28 08:02:10 9015
7 106 北京
2021-09-29 17:58:00 2021-09-29 18:01:00
9016
8 107 北京
2021-09-30 11:00:00 2021-09-30 11:01:00
9017
9 108 北京
2021-09-30 21:00:00 2021-09-30 21:01:00
9018
10 102 北京
2021-10-01 09:00:30 2021-10-01 09:01:00
9002
11
106
北京
2021-10-01 17:58:00
2021-10-01 18:01:00
9006
12
101
北京
2021-10-02 08:28:10
2021-10-02 08:30:00
9001
13 107
北京
2021-10-02 11:00:00
2021-10-02 11:01:00
9007
14
108
北京
2021-10-02 21:00:00
2021-10-02 21:01:00
9008
15
103
北京
2021-10-02 07:59:00
2021-10-02 08:01:00
9003
16 104
北京
2021-10-03 07:59:20
2021-10-03 08:01:00
9004
17 109
北京
2021-10-03 18:00:00
2021-10-03 18:01:00
9009

(uid-用户ID, city-城市, event_time-打车时间, end_time-打车结束时间, order_id-订单号)


打车订单表tb_get_car_order

id order_id uid driver_id order_time start_time finish_time mileage fare grade
1 9011 101 211 2021-09-25 08:30:00
2021-09-25 08:31:00 2021-09-25 08:54:00
10
35 5
2 9012 102 211 2021-09-25 09:01:00 2021-09-25 09:01:50 2021-09-25 09:28:00
11 32 5
3 9013
103 212 2021-09-26 08:01:00 2021-09-26 08:03:00 2021-09-26 08:27:00
12 31 4
4 9023
104 213 2021-09-26 08:01:00 NULL 2021-09-26 08:27:00
NULL NULL NULL
5 9014
104 212 2021-09-27 08:01:00 2021-09-27 08:04:00 2021-09-27 08:21:00
11 31 5
6 9015
105 212 2021-09-28 08:02:10
2021-09-28 08:04:10 2021-09-28 08:25:10 12 31 4
7 9016
106
213
2021-09-29 18:01:00
2021-09-2
918:02:10
2021-09-29 18:23:00
11 39 4
8 9017
107 213 2021-09-3011:01:00 2021-09-30 11:01:40 2021-09-30 11:31:00
11 38 5
9 9018 108 214 2021-09-30 21:01:00 2021-09-30 21:02:50 2021-09-30 21:21:00 14 38 5
10 9002 102 202 2021-10-01 09:01:00 2021-10-01 0 9:06:00 2021-10-01 09:31:00
10 41.5 5
11 9006 106 203 2021-10-0118:01:00 2021-10-01 18:09:00 2021-10-01 18:31:00
8 25.5 4
12
9001
101 202 2021-10-02 08:30:00
NULL
2021-10-02 08:31:00
NULL
NULL
NULL
13 9007
107 203 2021-10-02 11:01:00
2021-10-02
11:07:00
2021-10-02 11:31:00
9.9 30 5
14
9008
108 204 2021-10-02 21:01:00
2021-10-02 21:10:00
2021-10-02 21:31:00
13.2 38 4
15
9003
103 202 2021-10-02 08:01:00
2021-10-02 08:15:00
2021-10-02 08:31:00
11 41.5 4
16
9004
104 202 2021-10-03 08:01:00
2021-10-03 08:13:00 2021-10-03 08:31:00
7.5 22 4
17
9009 109 204 2021-10-0318:01:00
NULL
2021-10-03 18:51:00
NULL NULL
NULL
(order_id-订单号, uid-用户ID, driver_id-司机ID, order_time-接单时间, start_time-开始计费的上车时间,  finish_time-订单完成时间, mileage-行驶里程数, fare-费用, grade-评分)


场景逻辑说明

  • 用户提交打车请求后,在用户打车记录表生成一条打车记录,order_id-订单号设为null

  • 当有司机接单时,在打车订单表生成一条订单,填充order_time-接单时间及其左边的字段,start_time-开始计费的上车时间及其右边的字段全部为null,并把order_id-订单号order_time-接单时间end_time-打车结束时间)写入打车记录表;若一直无司机接单,超时或中途用户主动取消打车,则记录end_time-打车结束时间

  • 若乘客上车前,乘客或司机点击取消订单,会将打车订单表对应订单的finish_time-订单完成时间填充为取消时间,其余字段设为null

  • 当司机接上乘客时,填充订单表中该start_time-开始计费的上车时间
  • 当订单完成时填充订单完成时间、里程数、费用;评分设为null,在用户给司机打1~5星评价后填充。


问题:请统计国庆头3天里,每天的近7日日均订单完成量和日均订单取消量,按日期升序排序。结果保留2位小数。

输出示例
示例输出如下
dt finish_num_7d cancel_num_7d
2021-10-01 1.43 0.14
2021-10-02
1.57 0.29
2021-10-03
1.57 0.29
解释:
2021年9月25到10月3日每天的订单完成量为:2、1、1、1、1、2、2、3、1;每天的订单取消量为:0、1、0、0、0、0、0、1、1;
因此10.1到10.3期间的近7日订单完成量分别为10、11、11,因此日均订单完成量为:1.43、1.57、1.57;
近7日订单取消量分别为1、2、2,因此日均订单取消量为0.14、0.29、0.29;

示例1

输入

DROP TABLE IF EXISTS tb_get_car_record,tb_get_car_order;
CREATE TABLE tb_get_car_record (
    id INT PRIMARY KEY AUTO_INCREMENT COMMENT '自增ID',
    uid INT NOT NULL COMMENT '用户ID',
    city VARCHAR(10) NOT NULL COMMENT '城市',
    event_time datetime COMMENT '打车时间',
    end_time datetime COMMENT '打车结束时间',
    order_id INT COMMENT '订单号'
) CHARACTER SET utf8 COLLATE utf8_bin;

CREATE TABLE tb_get_car_order (
    id INT PRIMARY KEY AUTO_INCREMENT COMMENT '自增ID',
    order_id INT NOT NULL COMMENT '订单号',
    uid INT NOT NULL COMMENT '用户ID',
    driver_id INT NOT NULL COMMENT '司机ID',
    order_time datetime COMMENT '接单时间',
    start_time datetime COMMENT '开始计费的上车时间',
    finish_time datetime COMMENT '订单结束时间',
    mileage FLOAT COMMENT '行驶里程数',
    fare FLOAT COMMENT '费用',
    grade TINYINT COMMENT '评分'
) CHARACTER SET utf8 COLLATE utf8_bin;

INSERT INTO tb_get_car_record(uid, city, event_time, end_time, order_id) VALUES
 (101, '北京', '2021-09-25 08:28:10', '2021-09-25 08:30:00', 9011),
 (102, '北京', '2021-09-25 09:00:30', '2021-09-25 09:01:00', 9012),
 (103, '北京', '2021-09-26 07:59:00', '2021-09-26 08:01:00', 9013),
 (104, '北京', '2021-09-26 07:59:00', '2021-09-26 08:01:00', 9023),
 (104, '北京', '2021-09-27 07:59:20', '2021-09-27 08:01:00', 9014),
 (105, '北京', '2021-09-28 08:00:00', '2021-09-28 08:02:10', 9015),
 (106, '北京', '2021-09-29 17:58:00', '2021-09-29 18:01:00', 9016),
 (107, '北京', '2021-09-30 11:00:00', '2021-09-30 11:01:00', 9017),
 (108, '北京', '2021-09-30 21:00:00', '2021-09-30 21:01:00', 9018),
 (102, '北京', '2021-10-01 09:00:30', '2021-10-01 09:01:00', 9002),
 (106, '北京', '2021-10-01 17:58:00', '2021-10-01 18:01:00', 9006),
 (101, '北京', '2021-10-02 08:28:10', '2021-10-02 08:30:00', 9001),
 (107, '北京', '2021-10-02 11:00:00', '2021-10-02 11:01:00', 9007),
 (108, '北京', '2021-10-02 21:00:00', '2021-10-02 21:01:00', 9008),
 (103, '北京', '2021-10-02 07:59:00', '2021-10-02 08:01:00', 9003),
 (104, '北京', '2021-10-03 07:59:20', '2021-10-03 08:01:00', 9004),
 (109, '北京', '2021-10-03 18:00:00', '2021-10-03 18:01:00', 9009);

INSERT INTO tb_get_car_order(order_id, uid, driver_id, order_time, start_time, finish_time, mileage, fare, grade) VALUES
 (9011, 101, 211, '2021-09-25 08:30:00', '2021-09-25 08:31:00', '2021-09-25 08:54:00', 10, 35, 5),
 (9012, 102, 211, '2021-09-25 09:01:00', '2021-09-25 09:01:50', '2021-09-25 09:28:00', 11, 32, 5),
 (9013, 103, 212, '2021-09-26 08:01:00', '2021-09-26 08:03:00', '2021-09-26 08:27:00', 12, 31, 4),
 (9023, 104, 213, '2021-09-26 08:01:00', null, '2021-09-26 08:27:00', null, null, null),
 (9014, 104, 212, '2021-09-27 08:01:00', '2021-09-27 08:04:00', '2021-09-27 08:21:00', 11, 31, 5),
 (9015, 105, 212, '2021-09-28 08:02:10', '2021-09-28 08:04:10', '2021-09-28 08:25:10', 12, 31, 4),
 (9016, 106, 213, '2021-09-29 18:01:00', '2021-09-29 18:02:10', '2021-09-29 18:23:00', 11, 39, 4),
 (9017, 107, 213, '2021-09-30 11:01:00', '2021-09-30 11:01:40', '2021-09-30 11:31:00', 11, 38, 5),
 (9018, 108, 214, '2021-09-30 21:01:00', '2021-09-30 21:02:50', '2021-09-30 21:21:00', 14, 38, 5),
 (9002, 102, 202, '2021-10-01 09:01:00', '2021-10-01 09:06:00', '2021-10-01 09:31:00', 10.0, 41.5, 5),
 (9006, 106, 203, '2021-10-01 18:01:00', '2021-10-01 18:09:00', '2021-10-01 18:31:00', 8.0, 25.5, 4),
 (9001, 101, 202, '2021-10-02 08:30:00', null, '2021-10-02 08:31:00', null, null, null),
 (9007, 107, 203, '2021-10-02 11:01:00', '2021-10-02 11:07:00', '2021-10-02 11:31:00', 9.9, 30, 5),
 (9008, 108, 204, '2021-10-02 21:01:00', '2021-10-02 21:10:00', '2021-10-02 21:31:00', 13.2, 38, 4),
 (9003, 103, 202, '2021-10-02 08:01:00', '2021-10-02 08:15:00', '2021-10-02 08:31:00', 11.0, 41.5, 4),
 (9004, 104, 202, '2021-10-03 08:01:00', '2021-10-03 08:13:00', '2021-10-03 08:31:00', 7.5, 22, 4),
 (9009, 109, 204, '2021-10-03 18:01:00', null, '2021-10-03 18:51:00', null, null, null);

输出

2021-10-01|1.43|0.14
2021-10-02|1.57|0.29
2021-10-03|1.57|0.29
①用的方法是求前几行的累计和:
sum(column1) over (order by column2 rows N preceding)
只不过在这里将sum换成了avg,即:
avg(column1) over (order by column2 rows N preceding)
因为题目中说的进7日,所以就是N=6------本行+本行前面的6行。
②至于求每天的完成的订单数量---count(start_time)
求每天被取消的订单的数量-----sum(case when start_time is null then 1 else 0 end)
总结下来整个程序就是这样的:
select * from 
(select date_format(order_time,'%Y-%m-%d') dt,
round(avg(count(start_time)) over (order by date_format(order_time,'%Y-%m-%d')  rows 6 preceding),2) finish_num_7d,
round(avg(sum(case when start_time is null then 1 else 0 end)) over (order by date_format(order_time,'%Y-%m-%d') rows 6 preceding),2) cancel_num_7d
from tb_get_car_order
group by dt) as a 
where dt between '2021-10-01' and '2021-10-03'
order by dt



发表于 2021-12-06 09:31:10 回复(15)
select *
from
(select date(order_time) as dt,
       round(avg(count(start_time)) over(order by date(order_time) rows between 6 preceding and current row),2) as finish_num_7d,
       round(avg(sum(if(start_time is null,1,0))) over(order by date(order_time) rows between 6 preceding and current row),2) as cancel_num_7d
from tb_get_car_order
group by date(order_time)) as t
where dt between '2021-10-01' and '2021-10-03'
注意:
1.where 语句筛选必须在窗口函数层外面一层,不能直接筛选。
2.round函数不能用在开窗语句前,round(avg(),2) over()是不对的,
应该是round(avg() over(),2)
3.窗口函数划定范围语句:
avg(字段名) over(
        partition by 用于分组的列名 order by 用于排序的列名 asc/desc rows between A and B)

rows between 2 preceding and current row #取当前行和前面两行

rows between unbounded preceding and current row #包括本行和之前所有的行

rows between current row and unbounded following #包括本行和之前所有的行

rows between 3 preceding and current row #包括本行和前面三行

rows between 3 preceing and 1 following #从前面三行和下面一行,总共五行
发表于 2022-02-04 14:46:02 回复(1)
SELECT 
  dt,
  ROUND(SUM(finish_cnt) OVER w / 7, 2) finish_sum_7d,
  ROUND(SUM(cancel_cnt) OVER w / 7, 2) cancel_sum_7d
FROM (
SELECT
  DATE(finish_time) dt,
  SUM(start_time IS NOT NULL) finish_cnt,
  SUM(start_time IS NULL) cancel_cnt
FROM tb_get_car_order
WHERE DATE(order_time) BETWEEN '2021-09-25' AND '2021-10-03'
GROUP BY 1
) t 
WINDOW w AS (ORDER BY dt DESC ROWS BETWEEN CURRENT ROW AND 6 FOLLOWING)
ORDER BY 1
LIMIT 6, 3

发表于 2021-12-05 11:34:48 回复(1)
  • 如果天数是连续的,也就是说9月25到10月3日每天都有订单,
可以使用窗口函数
先对日期排序,然后取前六行和当前行
rows between 2 preceding and current row
  • 如果天数不连续,中间有间断
例如9月26断了一天,那么统计10月2号的时候会把9月25号给统计进去
这个时候我们可以使用表的自链接,并在on后添加近七天的链接条件
  • 下面给出整体的思路和代码
首先建立基础查询表
算出9月25到10月3日每一天的接单量和未成单量
with temp as
(
select
date(order_time) as dt,
count(fare) as finish_order,
sum(if(start_time is null,1,0)) as unfinish_order
from tb_get_car_order
where date(order_time) between '2021-09-25' and '2021-10-03'
group by dt
)
然后在此之上,使用表的自链接,
链接条件是对a表的10.1-10.3中每一天,b中的日期介于a中天数和a-6天之间
select 
    a.dt as dt,
    b.dt as dt2,
    b.finish_order as finish_order,
    b.unfinish_order as unfinish_order
from temp a
join temp b 
    on b.dt>=date_sub(a.dt,interval 6 day) and b.dt<=a.dt
where a.dt between '2021-10-01' and '2021-10-03'
由此条件得到的是一个行数为3*7的表

然后我们根据上表,对10月1-3号分组计算即可
select 
dt,
round(sum(finish_order)/count(dt2),2) as finish_num_7d,
round(sum(unfinish_order)/count(dt2),2) as cancel_num_7d
from temp2
group by dt
order by dt
完整代码如下
with temp as
(
select
date(order_time) as dt,
count(fare) as finish_order,
sum(if(start_time is null,1,0)) as unfinish_order
from tb_get_car_order
where date(order_time) between '2021-09-25' and '2021-10-03'
group by dt
)
,temp2 as
(
select 
    a.dt as dt,
    b.dt as dt2,
    b.finish_order as finish_order,
    b.unfinish_order as unfinish_order
from temp a
join temp b 
    on b.dt>=date_sub(a.dt,interval 6 day) and b.dt<=a.dt
where a.dt between '2021-10-01' and '2021-10-03'
# order by a.dt
)

select 
dt,
round(sum(finish_order)/count(dt2),2) as finish_num_7d,
round(sum(unfinish_order)/count(dt2),2) as cancel_num_7d
from temp2
group by dt
order by dt
发表于 2022-05-20 17:29:05 回复(3)
窗口函数最好用range模式. 因为用在rows模式下, 如果有一天没有发生订单的话, 汇总的数据就不对了
发表于 2022-12-17 18:34:08 回复(0)
with day as(
    SELECT
        DATE_FORMAT(order_time,'%Y-%m-%d') order_day,
        DATE_FORMAT(start_time,'%Y-%m-%d') start_day
    FROM tb_get_car_order
)
select 
    t.order_day,
    round(count(t1.start_day)/7,2) finish_num,
    round(sum(isnull(t1.start_day))/7,2) concel_num
from (select distinct order_day from day where order_day in ('2021-10-01','2021-10-02','2021-10-03')) t
left join day t1
on DATEDIFF(t.order_day,t1.order_day)<7 and DATEDIFF(t.order_day,t1.order_day)>=0
group by t.order_day
order by t.order_day asc
;

发表于 2021-12-14 12:28:19 回复(1)
WITH t1 as (
    SELECT DISTINCT DATE(order_time) dt FROM tb_get_car_order
    WHERE DATE(order_time) BETWEEN '2021-10-01' AND '2021-10-03'),
t2 as (
    SELECT DATE(order_time) order1_dt,order_id
    FROM tb_get_car_order
    WHERE fare IS NOT NULL
),
t3 as (
    SELECT DATE(order_time) order2_dt,order_id
    FROM tb_get_car_order
    WHERE fare IS NULL
)
SELECT dt,ROUND(COUNT(distinct t2.order_id)/7,2) finish_num_7d,
ROUND(count(distinct t3.order_id)/7,2) cancel_num_7d
FROM t1 LEFT JOIN t2 ON datediff(dt,order1_dt) BETWEEN 0 AND 6
LEFT JOIN t3 ON datediff(dt,order2_dt) BETWEEN 0 AND 6
GROUP BY dt
ORDER BY dt;
想到了前面那个7日动销率的题
发表于 2022-04-16 11:31:07 回复(0)

想到了两种方法,都提交成功了。
不过个人更偏好方法2。

方法1:sum() over(range)

with a as(
    select date(order_time) as dt,
        count(start_time) as finish_per_d,
        count(*)-count(start_time) as cancel_per_d,
        datediff(max(date(order_time)),'2021-09-25') as dt_int
    from tb_get_car_order
    where date(order_time) between '2021-09-25' and '2021-10-03'
    group by date(order_time)
)
select dt
    ,round(sum(finish_per_d) over(order by dt_int range between 6 PRECEDING and CURRENT ROW)/7,2) as finish_num_7d 
    ,round(sum(cancel_per_d) over(order by dt_int range between 6 PRECEDING and CURRENT ROW)/7,2) as cancel_num_7d
from a
limit 3 offset 6

方法2:构造日期列,求笛卡尔积,然后聚合

with a as(
    select date(order_time) as dt,
        count(start_time) as finish_per_d,
        count(*)-count(start_time) as cancel_per_d
    from tb_get_car_order
    where date(order_time) between '2021-09-25' and '2021-10-03'
    group by date(order_time)
)
, b as (
    select '2021-10-01' as dt union select '2021-10-02' union select '2021-10-03'
)
select b.dt,
    round(sum(finish_per_d)/7,2) as finish_num_7d,
    round(sum(cancel_per_d)/7,2) as cancel_num_7d
from a join b on datediff(b.dt,a.dt) between 0 and 6
group by b.dt
order by b.dt
发表于 2022-03-13 22:36:40 回复(3)

求解

【类型】:聚合窗口函数高级用法

【场景】:近几日的数据情况
【分类】:高级聚合窗口函数—窗口函数的移动平均

分析思路

难点:

1.当有2个变量时如何处理:使用高级窗口函数或者笛卡尔积

(1)统计订单完成记录和取消记录

加时间限制条件是为了减少计算量

  • [条件] 国庆头3天里近7日的时间范围

  • [使用] group by dt_7

(2)统计国庆头3天里,每天的近7日日均订单完成量和日均订单取消量,按日期升序排序。结果保留2位小数

  • [使用] avg(finish_cut) over(order by dt_7 rows 6 preceding)
  • 或者 sum(finish_cut) over(order by dt_7 rows 6 preceding)/7

求解代码

方法一

with子句

with
    main as(
        #统计订单完成记录和取消记录(加时间限制是为了减少计算量)
        select
            date(finish_time) as dt_7,
            count(if(start_time is not null,order_id,null)) as finish_cut,
            count(if(start_time is null,order_id,null)) as cancel_cut
        from tb_get_car_order
        where date(finish_time) between '2021-09-25' and '2021-10-03'
        group by dt_7
        order by dt_7 desc
    )
#统计国庆头3天里,每天的近7日日均订单完成量和日均订单取消量,按日期升序排序。结果保留2位小数
select distinct
    dt_7 as dt,
    round(avg(finish_cut) over(order by dt_7 rows 6 preceding),2) as finish_num_7d,
    round(avg(cancel_cut) over(order by dt_7 rows 6 preceding),2) as cancel_num_7d
from main
order by dt_7
limit 6,3

统计订单完成记录和取消记录输出

1    2021-10-03|1|1    
2    2021-10-02|3|1    
3    2021-10-01|2|0    
4    2021-09-30|2|0        
5    2021-09-29|1|0        
6    2021-09-28|1|0        
7    2021-09-27|1|0        
8    2021-09-26|1|1        
9    2021-09-25|2|0

每天的近7日日均订单完成量和日均订单取消量输出

1    2021-09-25|0.29|0.00        
2    2021-09-26|0.43|0.14        
3    2021-09-27|0.57|0.14        
4    2021-09-28|0.71|0.14        
5    2021-09-29|0.86|0.14        
6    2021-09-30|1.14|0.14        
7    2021-10-01|1.43|0.14    
8    2021-10-02|1.57|0.29    
9    2021-10-03|1.57|0.29    

最后利用 limit 6,3 取国庆头3天。

方法二

from子查询

#统计国庆头3天里,每天的近7日日均订单完成量和日均订单取消量,按日期升序排序。结果保留2位小数
select distinct
    dt_7 as dt,
    round(sum(finish_cut) over(order by dt_7 rows 6 preceding)/7,2) as finish_num_7d,
    round(sum(cancel_cut) over(order by dt_7 rows 6 preceding)/7,2) as cancel_num_7d
from(
    #统计订单完成记录和取消记录(加时间限制是为了减少计算量)
    select
        date(finish_time) as dt_7,
        count(if(start_time is not null,order_id,null)) as finish_cut,
        count(if(start_time is null,order_id,null)) as cancel_cut
    from tb_get_car_order
    where date(finish_time) between '2021-09-25' and '2021-10-03'
    group by dt_7
    order by dt_7 desc
    ) main
order by dt_7
limit 6,3

方法三

不使用窗口函数 使用union连接所有行

优点:思路清晰、暴力破解

缺点:当求的天数变多或者有些天数不需要计算近7日的信息时,会出现计算代码繁杂和不能计算的情况

with
    main as(
        #统计订单完成记录和取消记录(加时间限制是为了减少计算量)
        select
            date(finish_time) as dt_7,
            count(if(start_time is not null,order_id,null)) as finish_cut,
            count(if(start_time is null,order_id,null)) as cancel_cut
        from tb_get_car_order
        where date(finish_time) between '2021-09-25' and '2021-10-03'
        group by dt_7
        order by dt_7 desc
    )
    ,attr as(
        #统计国庆第一天近7日日均订单完成量和日均订单取消量
        select
            '2021-10-01' as dt,
            round(sum(if(datediff('2021-10-01',dt_7) between 0 and 6,finish_cut,0))/7,2) as finish_num_7d,
            round(sum(if(datediff('2021-10-01',dt_7) between 0 and 6,cancel_cut,0))/7,2) as cancel_num_7d
        from main
    )
    ,attr1 as(
        #统计国庆第二天近7日日均订单完成量和日均订单取消量
        select
            '2021-10-02' as dt,
            round(sum(if(datediff('2021-10-02',dt_7) between 0 and 6,finish_cut,0))/7,2) as finish_num_7d,
            round(sum(if(datediff('2021-10-02',dt_7) between 0 and 6,cancel_cut,0))/7,2) as cancel_num_7d
        from main
    )
    ,attr2 as(
        #统计国庆第三天近7日日均订单完成量和日均订单取消量
        select
            '2021-10-03' as dt,
            round(sum(if(datediff('2021-10-03',dt_7) between 0 and 6,finish_cut,0))/7,2) as finish_num_7d,
            round(sum(if(datediff('2021-10-03',dt_7) between 0 and 6,cancel_cut,0))/7,2) as cancel_num_7d
        from main
    )

#统计国庆头3天里,每天的近7日日均订单完成量和日均订单取消量,按日期升序排序。结果保留2位小数
select *
from attr
union
select *
from attr1
union
select *
from attr2

方法四

不使用窗口函数 做笛卡尔积后查找近7日数据做处理

优点:当求的天数变多或者有些天数不需要计算近7日的信息时,也可以计算

with
    main as(
        #统计订单完成记录和取消记录(加时间限制是为了减少计算量)
        select
            date(finish_time) as dt_7,
            count(if(start_time is not null,order_id,null)) as finish_cut,
            count(if(start_time is null,order_id,null)) as cancel_cut
        from tb_get_car_order
        where date(finish_time) between '2021-09-25' and '2021-10-03'
        group by dt_7
        order by dt_7 desc
    )
    ,attr as(
        #得到国庆头三天日期(为了分别计算每个日期的近7日数据,先要得到头三天的日期)
        select distinct
            date(finish_time) as dt
        from tb_get_car_order
        where date(finish_time) between '2021-10-01' and '2021-10-03'
    )

#统计国庆头3天里,每天的近7日日均订单完成量和日均订单取消量,按日期升序排序。结果保留2位小数
select
    dt,
    round(sum(if(datediff(dt,dt_7) between 0 and 6,finish_cut,0))/7,2) as finish_num_7d,
    round(sum(if(datediff(dt,dt_7) between 0 and 6,cancel_cut,0))/7,2) as cancel_num_7d
from main,attr
group by dt
order by dt
发表于 2022-11-10 18:36:42 回复(0)
两种方法,一种不用窗口函数,一种用窗口函数
1.不用窗口函数
select distinct date(order_time) dt,
       round((select count(date(start_time))
        from tb_get_car_order t2
        where timestampdiff(day,date(order_time),date(t1.order_time)) between 0 and 6
       )/7,2) finish_num_7d,
       round((select sum(if(start_time is null,1,0))
        from tb_get_car_order t3
        where timestampdiff(day,date(order_time),date(t1.order_time)) between 0 and 6
       )/7,2) cancel_num_7d
from tb_get_car_order t1
where date(order_time) between '2021-10-01' and '2021-10-03'
order by dt
2.用窗口函数
select *
from
(select dt,
       round(sum(finish_num) over (order by dt rows 6 preceding)/7,2) finish_num_7d,
       round(sum(cancel_num) over (order by dt rows 6 preceding)/7,2) cancel_num_7d
from
(select distinct date(order_time) dt,
       count(start_time) finish_num,
       sum(if(start_time is null,1,0)) cancel_num
from tb_get_car_order
group by dt) tmp1 ) tmp2
where dt between '2021-10-01' and '2021-10-03'
order by dt


发表于 2022-08-22 10:58:03 回复(0)
with t3 as(select date(order_time) as dt,sum(if(start_time is null,1,0)) as cancel_num,
                                                                count(finish_time)-sum(if(start_time is null,1,0)) as finish_num
                from tb_get_car_order
                where date(order_time) between '2021-09-25' and '2021-10-03'
                group by dt),
     t4 as(select *,round(avg(cancel_num) over(order by dt rows between 6 preceding and current row),2) as cancel_num_7d,
                           round(avg(finish_num) over(order by dt rows between 6 preceding and current row),2) as finish_num_7d
              from t3)
select dt,finish_num_7d,cancel_num_7d
from t4
where dt between '2021-10-01' and '2021-10-03'
order by dt;
发表于 2022-05-07 16:14:31 回复(0)
select a,round(finish_num/7,2) finish_num_7d,round(finish_a/7,2) cancel_num_7d  from
(select a,sum(b) over(order by a rows 6 preceding) finish_num,sum(c) over(order by a rows 6 preceding) as finish_a
from (select date(finish_time) a,count(fare) b,sum(case when start_time is null then 1 else 0 end) as c from tb_get_car_order group by a)t)m
where a between '2021-10-01' and '2021-10-03'
order by a
切记日期筛选要在滑动窗口的上一层,不能在同一个查询语句里,别再忘了!!

发表于 2021-12-21 10:18:42 回复(1)
select*
from (select date(order_time) as dt,
round(avg(sum(if(start_time is null,0,1))) over(order by date(order_time) rows 6 preceding),2) finish_num_7d,
round(avg(sum(if(start_time is null,1,0))) over (order by date(order_time) rows 6 preceding),2) cancel_num_7d
from tb_get_car_order
group by dt) t0
where dt between '2021-10-01' and '2021-10-03'
order by dt

发表于 2023-10-21 21:53:59 回复(0)
# 提取国庆前三天日期
with t1 as (
select distinct date(order_time) as dt
from tb_get_car_order
where date(order_time) between '2021-10-01' and '2021-10-03')

# 统计国庆前三天日期的7日内数据
select t1.dt,
       round(sum(if(start_time is not null, 1, 0))/7, 2) as finish_num_7d,
       round(sum(if(start_time is null, 1, 0))/7, 2) as cancel_num_7d
from tb_get_car_order o join t1 on datediff(t1.dt, o.order_time) between 0 and 6
group by 1
order by 1

发表于 2023-08-15 12:38:20 回复(0)
with dim_date as (
select '2021-10-01' as dt union all
select '2021-10-02' as dt union all 
select '2021-10-03' as dt 
) 

select 
t1.dt,
round(count(start_time)/7,2) as finish_num_7d,
round(sum(if(start_time is null,1,0))/7,2) as cancel_num_7d
from dim_date  t1 
left join tb_get_car_order t2 
 on datediff(t1.dt, date(t2.order_time)) between  0 and 6 
group by t1.dt

发表于 2023-08-10 11:49:35 回复(0)
with t as (
    select
        date(finish_time) dt,
        round(avg(count(start_time)) over(order by date(finish_time) rows 6 preceding),2) finish_num_7d,
        round(avg(sum(isnull(start_time))) over(order by date(finish_time) rows 6 preceding),2) cancel_num_7d
    from tb_get_car_order
    group by dt
)
select * from t where dt between '2021-10-01' and '2021-10-03' order by dt;

发表于 2023-08-04 13:36:16 回复(0)
滑动窗口例题
with total_info as( #先建大宽表
    select tgco.*, tgcr.city,tgcr.event_time,tgcr.end_time
    from tb_get_car_record tgcr
    join tb_get_car_order tgco
    on tgcr.uid=tgco.uid and tgcr.order_id=tgco.order_id
)
,
t1 as(
    select date_format(order_time,"%Y-%m-%d") as dt,
    count(case  when mileage is not null then 1 else null end) as finish_num,
    count(case  when mileage is null and finish_time is not null then 1 else null end) as cancel_num
    from total_info
    group by date_format(order_time,"%Y-%m-%d")
)


# 滑动窗口
select * from(
SELECT 
    dt,
    ROUND(AVG(finish_num) OVER (
        ORDER BY STR_TO_DATE(dt, '%Y-%m-%d') 
        ROWS BETWEEN 6 PRECEDING AND CURRENT ROW
    )
    ,2) AS finish_num_7d
    ,
    ROUND(AVG(cancel_num) OVER (
        ORDER BY STR_TO_DATE(dt, '%Y-%m-%d') 
        ROWS BETWEEN 6 PRECEDING AND CURRENT ROW
    )
    ,2) AS cancel_num_7d
FROM 
    t1
) t2
where dt between date("2021-10-01") and date("2021-10-03")
order by dt asc




发表于 2023-03-22 15:14:56 回复(0)
select *
from 
(
    select date(order_time) dt,
round(avg(count(start_time)) over(order by date(order_time) range interval 6 day preceding),2) as finish_num_7d,
round(avg(sum(case when start_time is null then 1 else 0 end)) over(order by date(order_time) range interval 6 day preceding),2) as cancel_num_7d
from tb_get_car_order 
group by dt
) t
where dt between '2021-10-01' and '2021-10-03'

发表于 2023-03-11 15:22:57 回复(0)
select *
from (select date(order_time) dt,
             round(sum(count(start_time)) over(order by date(order_time) rows 6 preceding) / 7,2),
             round(sum(count(if(start_time is null,1,null))) over(order by date(order_time) rows 6 preceding) / 7,2)
      from tb_get_car_order 
      group by date(order_time)) t
having dt in ("2021-10-01","2021-10-02","2021-10-03")
order by dt

发表于 2022-12-21 16:33:18 回复(0)
select * from (
    select dt,
    round(avg(finish_num) over(order by dt rows 6 preceding),2) as finish_num_7d,
    round(avg(cancel_num) over(order by dt rows 6 preceding),2) as cancel_num_7d
    from (
        select date(order_time) as dt,
        count(start_time) as finish_num,
        sum(start_time is null) as cancel_num
        from tb_get_car_order
        group by dt
    )t1
)as t2
where dt between '2021-10-01' and '2021-10-03'
order by dt;

发表于 2022-12-03 10:12:02 回复(0)