欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

SQL | explode+lateral view和其余sql常用函数

程序员文章站 2024-03-12 17:25:56
...

目录

背景

实习时遇到的一个场景。

  • 用sql从数据库中提取数据,并且将数据转成所需要的格式
  • 其次对转换后数据放到本地的Python环境中进行预处理建模。
  • 解释模型与上线

下面主要总结一下sql提数的过程,后面两个步骤前面的推文 涉及到一部分,后面还会更新~敬请期待。

数据长什么样?需求是什么呢?

原始数据

import pandas as pd
df1 = pd.read_excel('./sql数据处理与提取-0326.xlsx', sheet_name='原始')
df1
deviceid categoryinterest
0 456344159 军事:4.412,要闻:0.856,社会:0.543,娱乐/综艺:0.472,娱乐/电视:0...
1 537762486 军事:2.266,社会:1.115,体育/羽毛球:1.038,情感:0.321,娱乐:0.2...
2 842923625 动物/宠物:0.389,历史/近现代史:0.299,未知:0.296,时尚/时装:0.266...
3 000000C7KP39VGIV 动漫/日韩动漫:1.0,动漫:0.549,音乐:0.526,游戏/联机游戏:0.478,游戏...
4 000000C7KP3RJC7W 奇闻趣事:0.881,娱乐/明星八卦:0.831,娱乐:0.823,社会/事故:0.0,社会...

最终想要的数据

形成3列:

  • 一列是deviceid
  • 一列是categoryinterest中的 category,也就是兴趣点
  • 第三列是兴趣点对应的得分

其中一个id对应的多个类别的时候,打散开来,就是一个id对应有n个类别,那么就拆分成n行

df3 = pd.read_excel('./sql数据处理与提取-0326.xlsx', sheet_name='完全分开')
df3[['deviceid', 'interests_news', 'interests_score']]
deviceid interests_news interests_score
0 65762973 体育/冰雪运动 0.641
1 774830731 历史/古代史 1.000
2 65762973 人文/人文科普 0.584
3 124901984 体育/NBA 0.566
4 874657455 体育/乒乓球 0.207

处理的思路

  • 先根据逗号将 categoryinterest 一行一行的分出来,可以使用explode函数
  • 其次对分出来的部分(比如:娱乐/综艺:0.472)根据冒号进行切分,形成两列
  • 最后选择所需要的列

tips:

  • 最后都加一下groupby 防止重复的数据 也就相当于起到了去重的作用。测试一下Python相同两列的groupby 是否只有一行了?

测试Python中groupby

df_test = pd.DataFrame({'a': [1,1,3,4], 'a': [1,1,3,4], 
                        'b':[1,1,24,2], 'd': [2,2,8,1]})
df_test
a b d
0 1 1 2
1 1 1 2
2 3 24 8
3 4 2 1
dfg = df_test.groupby('a')
for d in dfg:
    print(d[0])
    print(d[1])
1
   a  b  d
0  1  1  2
1  1  1  2
3
   a   b  d
2  3  24  8
4
   a  b  d
3  4  2  1

结论:

  • SQL的groupby之后即使两列相同也都还会保留
  • 那问题来了?如果有缺失值会保留吗?测试一下

测试含有缺失值的groupby

import numpy as np
df_test = pd.DataFrame({'a': [1,1,3,4,np.nan], 'a': [1,1,3,4,np.nan], 
                        'b':[1,1,24,2,np.nan], 'd': [2,2,8,1,np.nan],
                        })
df_test
a b d
0 1.0 1.0 2.0
1 1.0 1.0 2.0
2 3.0 24.0 8.0
3 4.0 2.0 1.0
4 NaN NaN NaN
dfg = df_test.groupby('a')
for d in dfg:
    print(d[0])
    print(d[1])
1.0
     a    b    d
0  1.0  1.0  2.0
1  1.0  1.0  2.0
3.0
     a     b    d
2  3.0  24.0  8.0
4.0
     a    b    d
3  4.0  2.0  1.0

结论:

  • groupby会自动过滤掉含有缺失值的行!就不在一起去考虑了!

正题-如何上面说的思路?

首先explode一行每个逗号之间的内容

select
deviceid,categoryinterest,interests1
from
tb 
lateral view explode(split(categoryinterest,',')) tb1 as interests1 
# explode就是将hive一行中复杂的array或者map结构拆分成多行
# lateral view与explode等udtf就是天生好搭档,explode将复杂结构一行拆成多行,然后再用lateral view做各种聚合。
where
day=20190101
group by
deviceid,categoryinterest,interests1
limit 5

核心点:

  • explode函数 以及 lateral view 联合使用
  • 最后得加上group by 起到去重的作用

实现效果如下

df2 = pd.read_excel('./sql数据处理与提取-0326.xlsx', sheet_name='explode后')
df2
deviceid categoryinterest interests1
0 65762973 军事:1.0,娱乐:0.917,军事/装备:0.916,娱乐/明星八卦:0.874,历史/古... 体育/冰雪运动:0.641
1 774830731 历史/古代史:1.0,历史:0.5 历史/古代史:1.0
2 65762973 军事:1.0,娱乐:0.917,军事/装备:0.916,娱乐/明星八卦:0.874,历史/古... 人文/人文科普:0.584
3 124901984 情感/两性:1.0,历史/古代史:0.933,娱乐:0.901,情感:0.742,体育/乒乓... 体育/NBA:0.566
4 874657455 体育/国际足球:9.063,体育/中国足球:3.019,娱乐/综艺:1.947,体育/NBA... 体育/乒乓球:0.207

总结:

  • explode就是将sql或者hive一行中复杂的array或者map结构拆分成多行。
  • lateral view(侧视图)的意义是配合explode(或者其他的UDTF),一个语句生成把单行数据拆解成多行后的数据结果集。形成的虚拟表tb1 相当于再和原表联结 形成了新表interests1
  • 直接使用explode 一次只能生成一个字段 要生成多列就是使用lateral view(侧视图)

参考资料1:https://blog.csdn.net/guodong2k/article/details/79459282

参考资料2:https://blog.csdn.net/bitcarmanlee/article/details/51926530

其次对于explode之后的再进行interests1的切割

select
deviceid,categoryinterest,interests1,split(interests1, ':')[0] as interests_news,split(interests1, ':')[1] as interests_score
from
    (select
    deviceid,categoryinterest,interests1
    from
    table
    lateral view explode(split(categoryinterest,',')) tb1 as interests1 
    # explode就是将hive一行中复杂的array或者map结构拆分成多行
    # lateral view与explode等udtf就是天生好搭档,explode将复杂结构一行拆成多行,然后再用lateral view做各种聚合。
    # tb1相当于虚拟表
    where
    day=20190313
    group by
    deviceid,categoryinterest,interests1
    )t1
limit 5

实现效果如下

df3
deviceid categoryinterest interests1 interests_news interests_score
0 65762973 军事:1.0,娱乐:0.917,军事/装备:0.916,娱乐/明星八卦:0.874,历史/古... 体育/冰雪运动:0.641 体育/冰雪运动 0.641
1 774830731 历史/古代史:1.0,历史:0.5 历史/古代史:1.0 历史/古代史 1.000
2 65762973 军事:1.0,娱乐:0.917,军事/装备:0.916,娱乐/明星八卦:0.874,历史/古... 人文/人文科普:0.584 人文/人文科普 0.584
3 124901984 情感/两性:1.0,历史/古代史:0.933,娱乐:0.901,情感:0.742,体育/乒乓... 体育/NBA:0.566 体育/NBA 0.566
4 874657455 体育/国际足球:9.063,体育/中国足球:3.019,娱乐/综艺:1.947,体育/NBA... 体育/乒乓球:0.207 体育/乒乓球 0.207

总结:

  • 使用的是split函数,根据冒号进行切分
  • 其余情况类似

最后输出结果进行后续分析

封装成一个整体的sql语句

select
	actusers.device_uuid,interests.interests_news,interests.interests_score
from	

# 表1	
	(
	select
	day,app_id,device_uuid
	from
	table1 
	# 下面限定条件是为了取出一部分数据看看
	where
	day=20190101
	and app_id in ('2x1kfBk63z','2S5Wcx') 
	and current_channel_group='XXXX' 
	group by
	day,app_id,device_uuid 
	)actusers	

# 表2	
left join
	
	(select
	deviceid,interests_news,interests_score
	from
	(select
		deviceid,categoryinterest,interests1,split(interests1, ':')[0] as interests_news,split(interests1, ':')[1] as interests_score
	from
		(select
		deviceid,categoryinterest,interests1
		from
		table2
		lateral view explode(split(categoryinterest,',')) tb1 as interests1 
		# explode就是将hive一行中复杂的array或者map结构拆分成多行
		# lateral view与explode等udtf就是天生好搭档,explode将复杂结构一行拆成多行,然后再用lateral view做各种聚合。
		where
		day=20190101
		group by
		deviceid,categoryinterest,interests1
		)t1
	)t2
	where
	interests_score>=0.5 and interests_score<=1
	group by
	deviceid,interests_news,interests_score
	)interests
on	
	actusers.device_uuid=interests.deviceid
group by
	actusers.device_uuid,interests.interests_news,interests.interests_score

整体总结

  • 多重SQL嵌套从最里面的select往外看
  • explode用于将一个id对应多个内容 想把其分开成每一行的时候,但是explode只能生成一列,如果想多列,使用lateral view 侧视图
  • split函数是一个很好用的函数 一次是用在explode的时候,即根据逗号进行explode,另一次是用在select语句中,是直接生成新的变量,需要根据select的结果来进行变量的赋值!
  • sql中的去重一个是可以用distinct 一个是用groupby