行列之间的互相转换是ETL中的常见需求,在Spark SQL中,行转列有内建的PIVOT函数可用,没什么特别之处。而列转行要稍微麻烦点。本文整理了2种可行的列转行方法,供参考。

本文链接:https://www.cnblogs.com/hhelibeb/p/10310369.html

测试数据准备

本文的环境是Windows 10, Spark 2.4,开发语言是Python。首先构建一点初始测试数据,

from pyspark.sql import SparkSession

spark = SparkSession.builder.appName('TestAPP').enableHiveSupport().getOrCreate()

df = spark.createDataFrame([('数学','张三',88), ('语文','张三',92), ('英语','张三',77),
('数学','王五',65), ('语文','王五',87), ('英语','王五',90),
('数学','李雷',67), ('语文','李雷',33), ('英语','李雷',24),
('数学','宫九',77), ('语文','宫九',87), ('英语','宫九',90)
], ['科目','姓名','分数']).orderBy('科目') df.show()

执行程序,可以看到数据如下,

    +----+----+----+
|科目|姓名|分数|
+----+----+----+
|数学|张三| 88|
|数学|李雷| 67|
|数学|宫九| 77|
|数学|王五| 65|
|英语|张三| 77|
|英语|宫九| 90|
|英语|李雷| 24|
|英语|王五| 90|
|语文|李雷| 33|
|语文|宫九| 87|
|语文|张三| 92|
|语文|王五| 87|
+----+----+----+

行转列

如上述,使用PIVOT函数即可实现行转列,

df.createOrReplaceTempView('scores')

sql_content = '''select * from scores
pivot
(
sum(`分数`) for
`姓名` in ('张三','王五','李雷','宫九')
)
''' df_pivot = spark.sql(sql_content)
df_pivot.show()

得到结果,

+----+----+----+----+----+
|科目|张三|王五|李雷|宫九|
+----+----+----+----+----+
|数学| 88| 65| 67| 77|
|英语| 77| 90| 24| 90|
|语文| 92| 87| 33| 87|
+----+----+----+----+----+

列转行

本文整理的两种办法是使用Spark中的stack函数lateral view + explode函数

stack()

stack(n, expr1, ..., exprk) - 会将expr1, ..., exprk 分割为n行.

df_pivot.createOrReplaceTempView('v_pivot')

sql_content = '''select `科目`,
stack(4, '张三', `张三`, '王五', `王五`, '李雷', `李雷`, '宫九', `宫九`) as (`姓名`, `分数` )
from v_pivot
''' df_unpivot1 = spark.sql(sql_content) df_unpivot1.show()

可以看到,结果的结构和初始数据的结构相同,

+----+----+----+
|科目|姓名|分数|
+----+----+----+
|数学|张三| 88|
|数学|王五| 65|
|数学|李雷| 67|
|数学|宫九| 77|
|英语|张三| 77|
|英语|王五| 90|
|英语|李雷| 24|
|英语|宫九| 90|
|语文|张三| 92|
|语文|王五| 87|
|语文|李雷| 33|
|语文|宫九| 87|
+----+----+----+

lateral view + explode()

explode函数可以把数组分割为多行,比如,

> SELECT explode(array(10, 20));
10
20

lateral view使用表生成函数将每个输入行转换为0或多个输出行。最常见的用法是和explode函数一起使用。

sql_content = '''select `科目`, split(temp1, ':')[0] as `姓名`, split(temp1, ':')[1] as `分数`
from(
select `科目`, concat(
'张三:', `张三`, ',',
'王五:', `王五`, ',',
'李雷:', `李雷`, ',',
'宫九:', `宫九`
) temp
from v_pivot
) lateral view explode(split(temp, ',')) as temp1
'''
df_unpivot2 = spark.sql(sql_content) df_unpivot2.show()

结果同上,

+----+----+----+
|科目|姓名|分数|
+----+----+----+
|数学|张三| 88|
|数学|王五| 65|
|数学|李雷| 67|
|数学|宫九| 77|
|英语|张三| 77|
|英语|王五| 90|
|英语|李雷| 24|
|英语|宫九| 90|
|语文|张三| 92|
|语文|王五| 87|
|语文|李雷| 33|
|语文|宫九| 87|
+----+----+----+

参考链接:Spark SQL, Built-in Functions

Spark实现行列转换pivot和unpivot

hive lateral view 与 explode详解

SQL Guide

Spark SQL中列转行(UNPIVOT)的两种方法的更多相关文章

  1. .net中创建xml文件的两种方法

    .net中创建xml文件的两种方法 方法1:根据xml结构一步一步构建xml文档,保存文件(动态方式) 方法2:直接加载xml结构,保存文件(固定方式) 方法1:动态创建xml文档 根据传递的值,构建 ...

  2. 在Delphi中使用C++对象(两种方法,但都要改造C++提供的DLL)

    Delphi是市场上最好的RAD工具,但是现在C++占据着主导地位,有时针对一个问题很难找到Delphi或Pascal的解决方案.可是却可能找到了一个相关的C++类.本文描述几种在Delphi代码中使 ...

  3. Oracle中spool命令实现的两种方法比较

    ---恢复内容开始--- 要输出符合要求格式的数据文件只需在select时用字符连接来规范格式.比如有如下表 SQL>; select id,username,password from myu ...

  4. 在List中找出最大值的两种方法

    先说需求:找出一个对象List中,某个属性值最大的对象. 1.定义对象 private class A { public int ID { get; set; } public string Name ...

  5. 在shell script中进行数值运算的两种方法

    方法1:使用"$((计算式))"的方式进行数值运算,不需要使用declare命令显示声明数值型变量来存储计算结果: 方法2:使用declare命令配合"-i"选 ...

  6. Android中Intent传递对象的两种方法(Serializable,Parcelable)

    今天要给大家讲一下Android中 Intent中如何传递对象,就我目前所知道的有两种方法,一种是Bundle.putSerializable(Key,Object);另一种是 Bundle.putP ...

  7. Python 中格式化字符串 % 和 format 两种方法之间的区别

    Python2.6引入了 format 格式化字符串的方法,现在格式化字符串有两种方法,就是 % 和 format ,具体这两种方法有什么区别呢?请看以下解析. # 定义一个坐标值 c = (250, ...

  8. [转]Android中Intent传递对象的两种方法(Serializable,Parcelable)

    http://blog.csdn.net/xyz_lmn/article/details/5908355 今天要给大家讲一下Android中Intent中如何传递对象,就我目前所知道的有两种方法,一种 ...

  9. Android高手进阶教程(十七)之---Android中Intent传递对象的两种方法(Serializable,Parcelable)!

    [转][原文] 大家好,好久不见,今天要给大家讲一下Android中Intent中如何传递对象,就我目前所知道的有两种方法,一种是Bundle.putSerializable(Key,Object); ...

随机推荐

  1. 【java提高】---queue集合

    queue集合 什么是Queue集合? 答:Queue用于模拟队列这种数据结构.队列通常是指“先进先出(FIFO)”的容器.队列的头部保存在队列中存放时间最长的元素,尾部保存存放时间最短的元素. 新元 ...

  2. redis 系列23 哨兵Sentinel (上)

    一.概述 Sentinel(哨岗或哨兵)是Redis的高可用解决方案:由一个或多个Sentinel实例(instance)组成的Sentinel系统(system)可以监视任意多个主服务器,以及这些主 ...

  3. Magicodes.WeiChat——V3.0(多租户)版本发布

    主要内容如下: 添加项目Magicodes.WeiChat.Data.Multitenant,全面支持多租户(基于EF已经ASP.NET Identity) 增加租户管理.租户成员管理.修改密码.公众 ...

  4. 痞子衡嵌入式:串口调试工具Jays-PyCOM诞生记(5)- 软件优化

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是串口调试工具Jays-PyCOM诞生之软件优化. 前面痞子衡已经初步实现了Jays-PyCOM的串口功能,并且通过了最基本的测试,但目前 ...

  5. ZooKeeper的三种典型应用场景

    引言 ZooKeeper是中典型的pub/sub模式的分布式数据管理与协调框架,开发人员可以使用它进行分布式数据的发布与订阅.另外,其丰富的数据节点类型可以交叉使用,配合Watcher事件通知机制,可 ...

  6. Golang垃圾回收机制(一)

    原文: http://legendtkl.com/2017/04/28/golang-gc/ 1. Golang GC 发展 Golang 从第一个版本以来,GC 一直是大家诟病最多的.但是每一个版本 ...

  7. Nunit的尝试

    (ps:没有代码,只有理论) 单元测试 单元测试(Unit Test)的一个测试用例(Test Case)是一小段代码,用于测试一个小的程序功能的行为是否正常,保证开发的功能子项能正确完成并实现其基本 ...

  8. 【转】Android 之最新最全的Intent传递数据方法

    原文地址:https://www.jianshu.com/p/1169dba99261 intent传递数据 为什么要和intent单独拿出来讲,因为Intent传递数据也是非常重要的 一.简单的传递 ...

  9. iptables配置管理

    iptables规则 内核netfilter的规则: iptables的规则: 基本操作 实践:往iptables中插入一条规则:禁止基于端口号为22的所有客户端访问(等于是禁止基于SSH的客户端连接 ...

  10. PHP实现微信随机红包算法和微信红包的架构设计简介

    微信红包的架构设计简介: 原文:https://www.zybuluo.com/yulin718/note/93148 @来源于QCon某高可用架构群整理,整理朱玉华. 背景:有某个朋友在朋友圈咨询微 ...