美团大数据面试SQL-计算用户首单是即时单的比例

一、题目

在外卖订单中,有时用户会指定订单的配送时间。现定义:如果用户下单日期与期望配送日期相同则认为是即时单,如果用户下单日期与期望配送时间不同则是预约单。每个用户下单时间最早的一单为用户首单,请计算用户首单中即时单的占比。

t_user_order

代码语言:javascript
复制
+-----------+----------+----------------------+--------------+
| order_id  | user_id  |      order_time      | desire_date  |
+-----------+----------+----------------------+--------------+
| 1001      | 001      | 2024-07-01 12:01:23  | 2024-07-01   |
| 1002      | 001      | 2024-07-01 12:03:23  | 2024-07-02   |
| 1003      | 002      | 2024-07-01 13:03:23  | 2024-07-02   |
| 1004      | 002      | 2024-07-01 13:07:23  | 2024-07-01   |
| 1005      | 003      | 2024-07-01 15:03:23  | 2024-07-01   |
+-----------+----------+----------------------+--------------+

二、分析

  1. 题目中给出了即时单和首单的定义,需要先找到每个用户的首单,然后进行判断是否是即时单;
  2. 计算完成之后,需要统计出共有多少首单,其中即时单的比例。

维度

评分

题目难度

⭐️⭐️⭐️

题目清晰度

⭐️⭐️⭐️⭐️⭐️

业务常见度

⭐️⭐️⭐️⭐️⭐️

三、SQL

1.找到用户首单,并判断是否是即时单

使用row_number函数,找到每个用户的首单,然后根据订单时间和预期送达时间判断是否是即时单

执行SQL

代码语言:javascript
复制
select order_id,
       user_id,
       order_time,
       desire_date,
       is_instant
from (select order_id,
             user_id,
             order_time,
             desire_date,
             if(to_date(order_time) = to_date(desire_date), 1, 0)              as is_instant,
             row_number() over (partition by user_id order by order_time asc ) as rn
      from t_user_order) t
where rn = 1

查询结果

代码语言:javascript
复制
+-----------+----------+----------------------+--------------+-------------+
| order_id  | user_id  |      order_time      | desire_date  | is_instant  |
+-----------+----------+----------------------+--------------+-------------+
| 1001      | 001      | 2024-07-01 12:01:23  | 2024-07-01   | 1           |
| 1003      | 002      | 2024-07-01 13:03:23  | 2024-07-02   | 0           |
| 1005      | 003      | 2024-07-01 15:03:23  | 2024-07-01   | 1           |
+-----------+----------+----------------------+--------------+-------------+

2.统计用户首单总单数和即时单数

执行SQL

代码语言:javascript
复制
select 
    count(case when is_instant = 1 then order_id end) as instant_cnt,
    count(order_id) as total_cnt
from (select order_id,
             user_id,
             order_time,
             desire_date,
             if(to_date(order_time) = to_date(desire_date), 1, 0)              as is_instant,
             row_number() over (partition by user_id order by order_time asc ) as rn
      from t_user_order) t
where rn = 1

查询结果

代码语言:javascript
复制
+--------------+------------+
| instant_cnt  | total_cnt  |
+--------------+------------+
| 2            | 3          |
+--------------+------------+

3.计算即时单比例

统计即时单单量除以总单量,得到用户首单即时单比例

代码语言:javascript
复制
select
    round(count(case when is_instant = 1 then order_id end)/count(order_id),2) as instant_per
from (select order_id,
             user_id,
             order_time,
             desire_date,
             if(to_date(order_time) = to_date(desire_date), 1, 0)              as is_instant,
             row_number() over (partition by user_id order by order_time asc ) as rn
      from t_user_order) t
where rn = 1

查询结果

代码语言:javascript
复制
+--------------+
| instant_per  |
+--------------+
| 0.67         |
+--------------+

四、建表语句和数据插入

代码语言:javascript
复制
--建表语句
CREATE TABLE t_user_order
(
order_id string COMMENT '订单ID',
user_id string COMMENT '用户ID',
order_time string comment '下单时间',
desire_date string comment '期望送达日期'
) COMMENT '用户订单记录表'
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t' 
;
--插入数据
insert into t_user_order
values
('1001','001','2024-07-01 12:01:23','2024-07-01'),
('1002','001','2024-07-01 12:03:23','2024-07-02'),
('1003','002','2024-07-01 13:03:23','2024-07-02'),
('1004','002','2024-07-01 13:07:23','2024-07-01'),
('1005','003','2024-07-01 15:03:23','2024-07-01')