问题:
查询来查找每个用户的确认率 ,用户的 确认率 是 'confirmed'
消息的数量除以请求的确认消息的总数。没有请求任何确认消息的用户的确认率为 0
。确认率四舍五入到 小数点后两位 。
一、数据
1934. 确认率
表: Signups
+----------------+----------+ | Column Name | Type | +----------------+----------+ | user_id | int | | time_stamp | datetime | +----------------+----------+ User_id是该表的主键。 每一行都包含ID为user_id的用户的注册时间信息。
表: Confirmations
+----------------+----------+ | Column Name | Type | +----------------+----------+ | user_id | int | | time_stamp | datetime | | action | ENUM | +----------------+----------+ (user_id, time_stamp)是该表的主键。 user_id是一个引用到注册表的外键。 action是类型为('confirmed', 'timeout')的ENUM 该表的每一行都表示ID为user_id的用户在time_stamp请求了一条确认消息,该确认消息要么被确认('confirmed'),要么被过期('timeout')。
二、目标
找到每个用户的确认率。
三、分析
1.因为需要找到每个用户的确认率 ,且没有请求任何确认消息的用户的确认率为 0
,所以需要将Signups表和Confirmations
两张表用左连接联合起来。
2.确认率是用在Confirmations表中
每个用户action列的总数除以用户在此表中出现的次数,因此要使用group by对用户的ID进行分组查询。
3.Confirmations表的
action列的类型为枚举类型,因此可以使用if语句进行判断,基本格式为:
IF(条件,值1,值2) —> 当条件为真时,返回值1,条件为假时,返回值2。
因此用户的确认数量为:COUNT(IF(Confirmations
.action = 'confirmed',1,null)) ;
用户的总数量为:COUNT(Signups.user_id
);
4.因为需要保留两位小数,因此可以使用ROUND函数进行操作。
四、代码
select
s.user_id,
round(count(if(c.action = 'confirmed',1,null)) / count(*),2) as confirmation_rate
/* 只有当action列的数据为confired时才会被count统计,否则就不统计,因此条件为假时,返回NULL值,因为count不计算空值 */
from Signups s
left join Confirmations c
on s.user_id = c.user_id -- 使用左连接,确保没有请求任何确认消息的用户也存在
group by s.user_id;
五、小结
代码主要考察了左连接的使用,左连接可以确保当两张表进行连接时,左表的数据全都表留;同时代码中使用了IF函数:IF(条件,值1,值2) —> 当条件为真时,返回值1,条件为假时,返回值2。