Skip to content

“书中自有颜如玉”,至少在那一刻我是愿意相信的,哈哈哈。

知识的力量在那一刻被具象化了。

缘由

她很着急地找到我,说是她的领导要让她做一个数据,比较着急,她尝试了很多方法都不太理想。要处理的数据说多也多,说不多也确实不算多,手动慢慢处理也可以做完,但是现在就是没有太多时间了。

看着她十分焦急,我也就当仁不让了。

凭借好多年都不怎么使用过Excel了,果然折腾了大约十分钟也是无果。

毕竟是从业十几年了,怎么可能在这样一个小事上翻车呢?更何况还是此情此景。

灵光一闪,我想到了DuckDB。

问题

现在有两张表格:直播时间表live和订单表order

  • 直播时间表

记录了主播直播的时间段。

日期直播时间段主播
2023-10-0819:20-21:30主播A
2023-10-0917:00-18:00主播A
2023-10-0919:00-21:00主播B
2023-10-0914:00-16:00主播C
2023-10-1014:00-15:30主播D
2023-10-1016:00-19:00主播D
2023-10-1013:30-14:00主播A
2023-10-1019:30-20:30主播C
  • 订单表

记录了主播直播时的用户下单数据。

支付时间金额
2023-10-10 18:27:22299
2023-10-10 18:15:29129
2023-10-10 18:05:01299
2023-10-10 17:49:30299
2023-10-10 17:48:57129
2023-10-10 17:37:4499
2023-10-10 16:33:02249
2023-10-10 21:50:11299
2023-10-10 13:38:4899

现在需要计算每位主播带来的成交金额?

这个场景在职场还是比较常见的,如果是你,你会怎么处理呢?如果有更好的处理方法,欢迎评论。

解决

且看我是如何一步步解决这个问题的

  1. 使用DBeave创建DuckDB数据库

对于该步骤还不熟悉的同学可以查看文章结尾的相关文章

  1. 查看数据
sql
select * from 'E:\live.csv';
select * from 'E:\order.csv';

  1. live表进行处理

我们的目的是要得到直播的开始时间和结束时间,所以需要先把直播时间段分割后,然后再与日期列进行合并。

sql
select *, string_split(直播时间段, '-') tm from 'E:\live.csv';

通过观察,使用string_split函数将字符串分割。分割后tm列为数组

然后将日期列与tm列拼接,生成start_timeend_time列。

sql
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

  1. 使用left join完成匹配

只要成交时间在主播直播时间段内则计为主播带来的成交,也就是我们需要匹配成交时间>直播开始时间且成交时间<直播结束时间。

sql
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;

  1. 导出匹配完成的结果表直播成交
sql
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的强大了,我们可以很方便的设置中间过程表和结果表。对于复杂的计算可以采用分层思维,从而简化整个计算过程。

  1. 计算主播的总金额
sql
select 主播, sum(金额) 总金额 from 'E:\直播成交.csv'
group by 主播;

至此,问题就得到了完美解决,心情美得很。

进阶

处理问题的过程很有趣,能够完美解决问题也会很有成就感。如果你也想深入了解DuckDB,可以关注公众号:遇码,回复duckdb获取官方文档。

遇码MeetCoding 开源技术社区