1.行转列
先说行转列是什么意思啊,假设有这样的数据,uid表示用户,time表示时刻,event表示用户这个时刻在干什么,我们保存到数据库中就是这样的
uid | time | event |
a | 09:01:00 | 睁眼 |
a | 09:02:00 | 找手机 |
a | 09:03:00 | 发呆 |
a | 09:04:00 | 洗脸 |
a | 09:05:00 | 刷牙 |
a | 09:06:00 | 吃饭 |
b | 13:01:00 | 玩手机 |
b | 13:02:00 | 发呆 |
b | 13:03:00 | 工作 |
但是很明显,这样看起来会很累,我们希望可以直观一点
uid | start_time | end_time | path |
a | 09:00:00 | 09:06:00 | [睁眼,找手机,发呆,洗脸,刷牙,吃饭,工作] |
b | 13:01:00 | 13:03:00 | [吃饭,玩手机,发呆,工作] |
这个可以清楚的看到,我们把用户的每一行的数据汇总到了一列中,即通常说的行转列
那么用sql怎么实现呢
select uid,min(time) as start_time,max(time) as end_time
,concat_ws(',',collect_list(evnet)) as path
from t_user_time_event
group by uid
非常的简单,我们通过group by对用户进行聚合,collect_list把用户的事件放到一个数组中,然后使用concat_ws进行连接,这样就可以得到用户的路径了
说明:collect_list 不去重,collect_set 去重。 evnet的数据类型要求是string
2.列转行
uid | path |
a | 09:01:00_睁眼,09:02:00_找手机,09:03:00_发呆,09:04:00_洗脸,09:05:00_刷牙,09:06:00_吃饭 |
b | 13:01:00_玩手机,13:02:00_发呆,13:03:00_工作 |
可以看到两个用户,后面是这个用户在某个时刻做的事情,我们想要path这一列转成行
uid | time | event |
a | 09:01:00 | 睁眼 |
a | 09:02:00 | 找手机 |
a | 09:03:00 | 发呆 |
a | 09:04:00 | 洗脸 |
a | 09:05:00 | 刷牙 |
a | 09:06:00 | 吃饭 |
b | 13:01:00 | 玩手机 |
b | 13:02:00 | 发呆 |
b | 13:03:00 | 工作 |
是的,没错,就是上面的那个case,这该怎么搞呢?
select uid
,split(time_event,'_')[0] as time
,split(time_event,'_')[1] as event
from t_user_path
lateral view explode(split(path,',')) t as time_event
有点复杂,可以分开来讲
split就是把路径切割成数组
split(path,',')
explode列表中的每个元素生成一行
explode(ARRAY) --列表中的每个元素生成一行
explode(MAP) --map中每个key-value对,生成一行,key为一列,value为一列
即
select explode(split(path,',')) as time_event
from t_user_path
得到的结果就是
time_event |
09:01:00_睁眼 |
09:02:00_找手机 |
09:03:00_发呆 |
09:04:00_洗脸 |
09:05:00_刷牙 |
09:06:00_吃饭 |
13:01:00_玩手机 |
13:02:00 _发呆 |
13:03:00_工作 |
然后再把用户给关联上
select uid,explode(split(path,',')) as time_event
from t_user_path
但是这样就会存在问题,因为explode函数存在的局限性
不能关联原有的表中的其他字段。
不能与group by、cluster by、distribute by、sort by联用。
不能进行UDTF嵌套。 不允许选择其他表达式。
也就是是说,explode解析后不能关联到咱们的uid,这肯定是不行的,我们要分析的是不同用户的行为。因此需要lateral view。
LATERAL VIEW udtf(expression) tableAlias AS columnAlias (',' columnAlias)*
Lateral view与用户定义的表生成函数(如explode())一起使用。正如在内置的表生成函数中提到的,UDTF为每个输入行生成零个或多个输出行。Lateral view首先将UDTF应用于基表的每一行,然后将产生的输出行连接到输入行,形成一个具有提供的表别名的虚拟表。
注:Lateral View通常和UDTF一起出现,为了解决UDTF不允许在select字段的问题
这是什么意思呢,据我不完全猜测,Lateral View把explode解析的行暂存为一个虚拟表,这个虚拟表呢与被select的字段进行join,然后得到最终的结果。