在处理一些复杂的逻辑时,python这种面向过程的语言比SQL更符合人的思维方式。相信很多同学都觉得,如果能用python来处理数据库中的数据就好了。那么今天它来了。先用python写一个处理复杂逻辑的自定义函数(一扬智),然后把函数代码嵌入SQL(狮子吼)组合成一整套技巧:UDF下面我用一个栗子来说明两者的一些处理数据过程中的区别,在介绍栗子之前,先介绍一些withas。就像在python中创建函数或类一样,withas用于创建中间表。简单介绍一下select*from(select*fromtablewhereedt='2021-03-30')a可以写成withaas(select*fromtablewhereedt='2021-03-30')select*froma简单的SQL看不出这样的优势(即使是a有点多余),但是当逻辑复杂的时候,我们可以看到这种语法的优势,它可以从底层提取中间表,让我们只关注当前使用的表,复杂的处理逻辑可以分解为简单的步骤。下表记录了用户使用APP过程中每条行为日志的时间戳。我们想统计用户今天使用了多少次app,每次的开始时间和结束时间分别是什么时候。如何解决这个问题呢??SQL实现方法先用withas建中间表(注意on和where条件)witht1as(selectx.uid,casewhenx.rank=1theny.timestamp_mselsex.timestamp_msendasstart_time,casewhenx.rank=1thenx.timestamp_mselsey.timestamp_msendasend_timefrom(selectuid,timestamp_ms,row_number()over(partitionbyuidorderbytimestamp_ms)rankfromtmp.tmpx)xleftouterjoin(selectuid,timestamp_ms,row_number()over(partitionbyuidorderbytimestamp_ms)rankfromtmp.tmpx)yonx.uid=y.uidandx.rank=y.rank-1wherex.rank=1ory.rankisnullorytimestamp_ms-x.timestamp_ms>=300)首先我们用开窗函数做减法,用where条件过滤出我们需要的列,其中x.rank=1提取第一行y.rank为null提取最后一个y.timestamp_ms-x.timestamp_ms>=300提取满足条件的行,如下:当然,这个结果不是我们想要的结果。需要结合上表中一行数据的结束时间和下一条数据的开始时间。构造好时间段,按照我们上面说的,那我们不用关心底层逻辑,关注这个中间表t1selecta.uid,end_timeasstart_time,start_timeasend_timefrom(selectuid,start_time,row_number()over(partitionbyuidorderbystart_time)asrankfromt1)ajoin(selectuid,end_time,row_number()over(partitionbyuidorderbyend_time)asrankfromt1)bona.uid=b.uidanda.rank=b.rank+1同理,排序后减去错位,就可以完工了~UDF实现方法首先的all,我们假设上面的数据是存储在csv中的,使用python处理本地文件data.csv,按照python的处理方式编写代码(这里就不每句解释了,懂python的同学可以跳过it,不知道怎么写的同学自己)deflife_cut(files):f=open(files)act_list=[]act_dict={}forlineinf:line_list=line.strip().split()key=tuple(line_list[0:1])ifkeynotinact_dict:act_dict.setdefault(key,[])act_dict[key].append(line_list[1])else:act_dict[key].append(line_list[1])fork,vinact_dict.items():k_str=k[0]+"\t"start_time=v[0]last_time=v[0]i=1while
