“书中自有颜如玉”,至少在那一刻我是愿意相信的,哈哈哈。
知识的力量在那一刻被具象化了。
缘由
她很着急地找到我,说是她的领导要让她做一个数据,比较着急,她尝试了很多方法都不太理想。要处理的数据说多也多,说不多也确实不算多,手动慢慢处理也可以做完,但是现在就是没有太多时间了。
看着她十分焦急,我也就当仁不让了。
凭借好多年都不怎么使用过Excel了,果然折腾了大约十分钟也是无果。
毕竟是从业十几年了,怎么可能在这样一个小事上翻车呢?更何况还是此情此景。
灵光一闪,我想到了DuckDB。
问题
现在有两张表格:直播时间表live
和订单表order
。
- 直播时间表
记录了主播直播的时间段。
日期 | 直播时间段 | 主播 |
---|---|---|
2023-10-08 | 19:20-21:30 | 主播A |
2023-10-09 | 17:00-18:00 | 主播A |
2023-10-09 | 19:00-21:00 | 主播B |
2023-10-09 | 14:00-16:00 | 主播C |
2023-10-10 | 14:00-15:30 | 主播D |
2023-10-10 | 16:00-19:00 | 主播D |
2023-10-10 | 13:30-14:00 | 主播A |
2023-10-10 | 19:30-20:30 | 主播C |
- 订单表
记录了主播直播时的用户下单数据。
支付时间 | 金额 |
---|---|
2023-10-10 18:27:22 | 299 |
2023-10-10 18:15:29 | 129 |
2023-10-10 18:05:01 | 299 |
2023-10-10 17:49:30 | 299 |
2023-10-10 17:48:57 | 129 |
2023-10-10 17:37:44 | 99 |
2023-10-10 16:33:02 | 249 |
2023-10-10 21:50:11 | 299 |
2023-10-10 13:38:48 | 99 |
现在需要计算每位主播带来的成交金额?
这个场景在职场还是比较常见的,如果是你,你会怎么处理呢?如果有更好的处理方法,欢迎评论。
解决
且看我是如何一步步解决这个问题的
- 使用DBeave创建DuckDB数据库
对于该步骤还不熟悉的同学可以查看文章结尾的相关文章
- 查看数据
select * from 'E:\live.csv';
select * from 'E:\order.csv';
- 对
live
表进行处理
我们的目的是要得到直播的开始时间和结束时间,所以需要先把直播时间段
分割后,然后再与日期
列进行合并。
select *, string_split(直播时间段, '-') tm from 'E:\live.csv';
通过观察,使用string_split
函数将字符串分割。分割后tm
列为数组
然后将日期
列与tm
列拼接,生成start_time
和end_time
列。
select *, strptime(concat(strftime(日期, '%Y-%m-%d'),' ', tm[1]), '%Y-%m-%d %H:%M') start_time, strptime(concat(strftime(if(tm[1]>if(tm[2]=='24:00', '00:00', tm[2]), 日期 + 1 , 日期), '%Y-%m-%d'),' ', if(tm[2]=='24:00', '00:00', tm[2])), '%Y-%m-%d %H:%M') end_time from (
select *, string_split(直播时间段, '-') tm from 'E:\live.csv');
此处有两个细节需要考虑:
如果直播时间段出现了跨天,如
23:00-01:00
,此时如果直接拼接就会出错,出现跨天,结束时间的日期需要+1才对,即如果结束时间小于了开始时间,则日期+1。对于结束时间刚好是零点,如
23:00-24:00
,但是也有人会登记成23:00-00:00
,为了适用于上条规则,此处判断了结束时间是否等于24:00
,如果是则变为00:00
- 使用
left join
完成匹配
只要成交时间在主播直播时间段内则计为主播带来的成交,也就是我们需要匹配成交时间>直播开始时间且成交时间<直播结束时间。
select * from 'E:\order.csv' o
left join (
select *, strptime(concat(strftime(日期, '%Y-%m-%d'),' ', tm[1]), '%Y-%m-%d %H:%M') start_time, strptime(concat(strftime(if(tm[1]>if(tm[2]=='24:00', '00:00', tm[2]), 日期 + 1 , 日期), '%Y-%m-%d'),' ', if(tm[2]=='24:00', '00:00', tm[2])), '%Y-%m-%d %H:%M') end_time from (
select *, string_split(直播时间段, '-') tm from 'E:\live.csv')) l
on o.支付时间 > l.start_time and o.支付时间 < l.end_time;
- 导出匹配完成的结果表
直播成交
copy (
select 支付时间, 金额, 日期, 直播时间段, 主播 from(
select * from 'E:\order.csv' o
left join (
select *, strptime(concat(strftime(日期, '%Y-%m-%d'),' ', tm[1]), '%Y-%m-%d %H:%M') start_time, strptime(concat(strftime(if(tm[1]>if(tm[2]=='24:00', '00:00', tm[2]), 日期 + 1 , 日期), '%Y-%m-%d'),' ', if(tm[2]=='24:00', '00:00', tm[2])), '%Y-%m-%d %H:%M') end_time from (
select *, string_split(直播时间段, '-') tm from 'E:\live.csv')) l on o.支付时间 > l.start_time and o.支付时间 < l.end_time) b) to 'E:\直播成交.csv';
此处使用了copy
方法,相信此刻你已经体会到DuckDB的强大了,我们可以很方便的设置中间过程表和结果表。对于复杂的计算可以采用分层思维,从而简化整个计算过程。
- 计算主播的总金额
select 主播, sum(金额) 总金额 from 'E:\直播成交.csv'
group by 主播;
至此,问题就得到了完美解决,心情美得很。
进阶
处理问题的过程很有趣,能够完美解决问题也会很有成就感。如果你也想深入了解DuckDB,可以关注公众号:遇码,回复duckdb获取官方文档。