> For the complete documentation index, see [llms.txt](https://houzidata.gitbook.io/sql/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://houzidata.gitbook.io/sql/di-5-zhang-xiang-mu-shi-zhan/tu-jie-mian-shi-ti-di-di-2020-qiu-zhi-zhen-ti.md).

# 图解面试题：滴滴 2020 求职真题

![](/files/-MV5x98tKwCYA-dGqDGF)

**【题目】**

“订单信息表” 里记录了巴西乘客使用打车软件的信息，包括订单呼叫、应答、取消、完单时间。（滴滴 2020 年笔试题）

![](/files/-MV5xgvNWW7fysr9Y4G-)

![](/files/-MV5xmN-3N8Sub1p5H-2)

注意：

（1）表中的时间是北京时间，巴西比中国慢 11 小时。

（2）应答时间列的数据值如果是 “1970” 年，表示该订单没有司机应答，属于无效订单。

![](/files/-MV5xprxastf8b_Yi5q-)

**问题**

1. 订单的应答率，完单率分别是多少？
2. 呼叫应答时间有多长？
3. 从这一周的数据来看，呼叫量最高的是哪一个小时（当地时间）？呼叫量最少的是哪一个小时（当地时间）？
4. 呼叫订单第二天继续呼叫的比例有多少？
5. （选做）如果要对乘客进行分类，你认为需要参考哪一些因素？

**【解题步骤】**

我们首先对数据进行预处理，将北京时间转化为巴西时间。具体需要分两步来实现，首先为了确保表中的时间为标准的日期格式，我们统一对其进行日期格式处理。然后再将处理后的日期转换成巴西时间。

![](/files/-MV5xtHQaxaSnJDzGI8M)

（1）日期格式化

由于在日期格式化中，我们会涉及到需要修改表中的日期数据，因此考虑用 update 语句。而修改表的具体操作会涉及到日期数据类型之间的转换，我们考虑用 cast 函数。

![](/files/-MV5xzAIDaak6BSbBwPm)

![](/files/-MV5y0t6m5LdHqXRD99w)

由于表中的时间应是 datetime 的格式，也就是精确到时分秒（YYYY-MM-DD HH:mm:ss）。转换后的效果如下图。

![](/files/-MV5y8NCyHDmx3N2UIht)

因此可以写出下列 sql 语句。

```sql
update 订单信息表 set call_time=cast(call_time as datetime);
update 订单信息表 set grab_time=cast(grab_time as datetime);
update 订单信息表 set cancel_time=cast(cancel_time as datetime);
update 订单信息表 set finish_time=cast(finish_time as datetime);
```

日期格式化后的表如下图。

![](/files/-MV5yCcT9tRDe62o9AbQ)

（2） 转换成巴西时间

由于数据中的时间为北京时间，而且已知巴西比中国慢 11 小时，因此我们这里使用 date\_sub 函数。

![](/files/-MV5yGPoeIC2bXIou6Ej)

因此可以写出下列 sql 语句：

```sql
update 订单信息表 
set call_time= date_sub(call_time, interval 11 hour) ;
update 订单信息表 
set grab_time= date_sub(grab_time, interval 11 hour) ;
update 订单信息表 
set cancel_time= date_sub(cancel_time, interval 11 hour) ;
update 订单信息表
set finish_time= date_sub(finish_time, interval 11 hour) ;
```

时间转换结果如下图：

![](/files/-MV5yN5BIlSPl9Kfm0Bz)

按照以上操作，数据日期预处理完成。

**1. 订单的应答率，完单率分别是多少？**

**（1）应答率**

应答率 = 应答订单数 / 呼叫订单数

![](/files/-MV5z-7f7NRqgHIK6IOW)

**呼叫订单：** 呼叫订单数等于呼叫时间（call\_time）这一列的数据总数，可以用 count(call\_time) 汇总。

**应答订单：**&#x5E94;答订单数等于应答时间（grab\_time）这一列的数据总数，可以用 count(grab\_time) 汇总。需要注意，这一列里的值**不等于‘1970’**&#x7684;数据的数量才是**有效**的应答订单数。如下图：红框的部分为应答订单。

![](/files/-MV5z2kBYBVe_gLR_YuU)

根据题目的业务要求，需要对不同的条件进行统计，在《猴子 从零学会 sql》里讲过条件判断要用 case when 表达式。所以应答订单数对应的 sql 是：

```sql
sum(case when grab_time <> 1970 then 1 else 0 end)
```

现在可以计算出指标 应答率 = 应答订单数 / 呼叫订单数 ：

```sql
select sum(case when grab_time <> 1970 then 1 else 0 end)/count(call_time) as 应答率
from 订单信息表;
```

查询结果如下：

![](/files/-MV5z8IDhTP75lJi06v7)

**（2）完单率**

完单率 = 完成订单数 / 呼叫订单数

![](/files/-MV5zCFCr6HPSqyQ3pZi)

**完成订单：** 完成时间（finish\_time）这一列中，值**不等于‘1970’**&#x7684;数据数量为**有效**的完成订单数。如下图：红框的部分为完成订单。

![](/files/-MV5zH1i9MtpqxhIOW0c)

所以完成订单数为：

```sql
sum(case when finish_time <> 1970 then 1 else 0 end)
```

现在可以计算出指标完单率 = 完成订单数 / 呼叫订单数 ：

```sql
select sum(case when finish_time <> 1970 then 1 else 0 end)/count(*) as 完单率
from 订单信息表;
```

查询结果如下

![](/files/-MV5zL8K0ZvqlY_J2reT)

**2. 呼叫应答时间有多长？**

根据题目中指标定义：

> 呼叫应答时间 = 被应答订单从呼叫到被应答时长总和 / 被应答订单数量

被应答订单从呼叫到被应答时长 = 被应答的时间（grab\_time） - 呼叫的时间（call\_time）。

这涉及到计算两个日期之间的差值，《猴子 从零学会 sql》里讲到对应单函数是 timestampdiff。下图是这个函数的用法。

![](/files/-MV5zQ11fcLikyH82aZ7)

我们回到题目，利用 timestampdiff 函数计算呼叫到被应答时长的总和。

![](/files/-MV5zV3dUFaVHbk4Pxqw)

综上，相应的 sql 语句分析如下

![](/files/-MV5zbRaWxPDlisG-5FF)

‍

查询结果如下

![](/files/-MV5zfia-VIP3WQ9zY_l)

**3.从这一周的数据来看，呼叫量最高的是哪一个小时（当地时间）？呼叫量最少的是哪一个小时（当地时间）？**

（1）时间转换

由于题目中要求的是 “哪一个小时”，因此我们首先将数据格式化转换成小时。新增一列来表示时间中的 “小时”, 列名设为 call\_time\_hour。

```sql
-- 添加列
alter table 订单信息表 add column call_time_hour varchar(255);
```

利用 date\_format 函数，用于以不同的格式显示日期数据，将将数据格式转换成小时。

```sql
/** 
给列添加数据
%k表示显示的是24小时制中的小时
*/
update 订单信息表
set call_time_hour=date_format(call_time,'%k');
```

转化后的表如下图

![](/files/-MV5zpt37mTPoqVD7HVk)

（2）呼叫量最高的是哪一个小时？

呼叫订单是 order\_id 列。按 “每个小时” 分组（group by call\_time\_hour），然后统计每个小时的呼叫订单量 count(order\_id)，然后排序就可以知道哪个小时的订单量最高。

下图给出 sql 语句分析过程：

![](/files/-MV5zwvL9iVt7JB-XEGe)

此时得到查询结果如下图

![](/files/-MV6-3S3ytWU-bC01AE5)

因为题目要求的是排序后的最大值（呼叫量最高的小时），可以用 limit 子句 来筛选出第一行数据。

![](/files/-MV6-7lUl_Yv_WsVsnqa)

sql 语句如下：

```sql
select call_time_hour,count(order_id) as 最大次数
from 订单信息表
group by call_time_hour
order by 最大次数 desc 
limit 1;
```

（3）呼叫量最少的是哪一个小时？

接着上面的排序结果，我们看到有 3 个呼叫小时的数据都为最小次数，用 limit 3 都将它们筛选出来即可。

![](/files/-MV6-CdNri-GlfPAxX2W)

```sql
select call_time_hour,count(order_id) as 最小次数
from 订单信息表
group by call_time_hour
order by 最小次数 asc 
limit 3;
```

**4.呼叫订单第二天继续呼叫的比例有多少？**

呼叫订单第二天继续呼叫的比例 = 第二天继续呼叫的用户量 / 总的呼叫订单量。

计算第二天继续呼叫的用户量的思路如下图：

![](/files/-MV6-Gps6TQRGUVQRthC)

我们具体分析看每一部分。

（1）自关联查询，求得呼叫的时间间隔。由于我们需要时间的单位为天，因此我们使用 date\_format 函数来提取出日期中的 “年月日” 部分。

![](/files/-MV6-Mktmj2rPJd4WF1x)

sql 语句如下：

```sql
-- 添加一列来显示时间中的“年月日”部分
alter table 订单信息表 add column call_time_day varchar(255);
update 订单信息表
set call_time_day=date_format(call_time,'%Y-%m-%d');
```

此时变化后的表如下：

![](/files/-MV6-T0gEDQQykqOgkUL)

我们接下来利用表的联结来计算相隔天数。这里由于涉及到计算相隔的天数之差，我们使用上面讲过的 timestampdiff 函数。单位为天。

![](/files/-MV6-kpYcULRidu2IuPA)

此时查询结果如下

![](/files/-MV6-paTnRt6urBbp-qc)

筛选出时间差为 1 天的数据，也就是间隔 = 1 的数据。

![](/files/-MV6-z_CTVFnxMF6H0IU)

利用子查询嵌套，将上面的查询结果作为新表，在其中做出筛选，并求和。sql 语句分析如下图。

![](/files/-MV602zU6RX5ITWsMmXP)

此时查询结果如下图

![](/files/-MV607-08tJe_tcLuqmk)

最后我们计算出第二天继续呼叫比例

![](/files/-MV60CLiDP4OJzrcLqJs)

查询结果如下图

![](/files/-MV60H8bkzJ06wrGbo7i)

**5.（选做）如果要对表中乘客进行分类，你认为需要参考哪一些因素？**

我们可以从以下两个角度来考虑对用户分类。

![](/files/-MV60LTO9-FpYaCQ9Ub4)

**用户行为分类**

1\) 根据完成时间和接单时间，可大致计算出乘客在乘车过程中所消耗的时间，对这个时间进行预判，属于长途、中途或者是短途，来分析乘客的乘车习惯。

2\) 根据呼叫时间可以判断乘客是在时间点发单的，乘客需求是如何产生的，可分析用户在哪些场景有乘车需求，上班、下班、就餐、出游、临时等场景。

**用户价值分类**

使用之前学过的 [RFM 分析方法](http://mp.weixin.qq.com/s?__biz=MzAxMTMwNTMxMQ==\&mid=2649246563\&idx=2\&sn=3ffe509999d144d23dec5acc101fc2ef\&chksm=835fc353b4284a45ce01391453fe2fec1b225bbd6bbdb67dd7f304aacdd4f21f60d0b27ba309\&scene=21#wechat_redirect)，对用户按价值分类。

![](/files/-MV60Oy2glgeM1ckE96j)

RFM 具体到本题可以做以下定义：

```sql
R：最近一次乘客的完单时间。
F：乘客打车的频率。
M：打车消费的金额。此处可以用乘车过程消耗的时长来代替等。
```

**【本题考点】**

1. 对日期数据的处理，掌握题目里讲过对常用日期处理方法。
2. 考查分析思维能力。使用学过的如何使用[数据分析解决问题的框架](http://mp.weixin.qq.com/s?__biz=MzAxMTMwNTMxMQ==\&mid=2649246563\&idx=2\&sn=3ffe509999d144d23dec5acc101fc2ef\&chksm=835fc353b4284a45ce01391453fe2fec1b225bbd6bbdb67dd7f304aacdd4f21f60d0b27ba309\&scene=21#wechat_redirect)来解决。

推荐：[如何从零学会 sql？](http://mp.weixin.qq.com/s?__biz=MzAxMTMwNTMxMQ==\&mid=2649247566\&idx=2\&sn=5af748b677eb72028764dde0577675fb\&chksm=835fc77eb4284e68e8cfe3f08c5a671b9e080b2651f20b40b1c793ffda4042ae43ad8f35a755\&scene=21#wechat_redirect)

![](/files/-MV60_LXZyk6XgFi6TFM)
