[原文链接](https://databricks.com/blog/2018/11/01/sql-pivot-converting-rows-to-columns.html)
引言
Pivot作为DataFrame的功能在Apache Spark 1.6被引入, 支持用户将单列数据转换为多列数据,Apache Spark 2.4版本扩展了这部分功能, 本文将以西雅图当地气温为基础,介绍如何通过SQL pivot实现复杂数据的转换。
Pivot气温检查
下表是今年西雅图7月气温最高的9天气温温度, 最高可达90华氏度!
假设我们想知道西雅图气温历史上是否存在过这种趋势,最直观的方法是将气温数据按照下列方式进行展示,月份作为列,年份作为行,值为当月平均最高气温,这种数据组织方式横向可以比较相邻月份的气温,纵向可以比较不同年份统一月份的平均最高气温
用户可以通过Spark SQL的Pivot功能来实现上述功能,下面为详细的Spark SQL语句
上述SQL语句输出如下:
SQL Pivot
下面我们来分析这个SQL语句是如何工作的, 首先需要指定FROM语句,该语句作为pivot语句的输入,在上述示例中FROM语句包含了年份,月份以及平均最高温度,其次PIVOT语句, 聚合函数avg作为PIVOT语句第一个参数指定需要聚合的列,接着在FOR语句中指定pivot列以及在IN算子指定Pivot列的值, pivot将依据列值转换为多列数据,我们还可以在IN中指定pivot列值别名,使输出列名更加易读,上述示例中为每个列值显示对应的月份。
Pivot可以根据隐式的group-by列以及pivot列进行分组,其中隐式的group-by列是出现在FROM语句中,但是没有出现在聚合函数或者pivot列中,上述查询中月份作为pivot列,年份作为隐式的group-by列, avg(temp)作为(year, month)键值对的值, month的值是在FOR语句指定的, 另外需要注意的是如果pivot输出不需要的列从FROM语句中剔除, 否则查询会产生与预期不一样的输出。
多聚合
上述PIVOT语句只包含一个聚合语句,显示用户会指定多个聚合语句,基于上述温度数据,我们列出6月份到9月份最高温度和最低温度。下面是SQL语句的示例:
在多聚合函数语句,列的名称是pivot列和聚合函数的笛卡尔乘积,名称格式为<value>_<aggExpr>, 下面是上述SQL语句的输出:
Grouping columns 和 Pivot Columns
假设我们要在温度趋势中包含最低温度,下表列举了每天的最低温度
我们通过UNION ALL语句把两张表合并,下面为合并语句
接着基于新生成的表执行Pivot查询
上述SQL语句可以获得过去4年每月的最低温度和最高温度,需要注意的是pivot查询包含flag列,否则会出现最高温度最低温度混合输出.
上述结果中,每年包含两行数据,分别为最高温度和最低温度,这是因为在pivot输入包含flag列,该列会作为pivot输出隐式group-by列, flag除了可以作为group-by的列,还可以作为pivot列,这样就可以拥有两个pivot列:month和flag, 示例SQL语句如下:
输出结果与flag作为group-by有所不同,如下所示,每行表示一年数据,每月的数据包含两列