SQL - 如何对数组的元素求和?

SQL - How can I sum elements of an array?

我正在将 SQL 与 pyspark 和 hive 一起使用,我是新手。 我有一个带有字符串类型列的配置单元 table,如下所示:

id | values
1  | '2;4;4'
2  |  '5;1'
3  |  '8;0;4'

我想创建一个查询来获取这个:

id | values | sum
1  | '2.2;4;4'  | 10.2
2  |  '5;1.2' |  6.2
3  |  '8;0;4' | 12

通过使用 split(values, ';') 我可以获得像 ['2.2','4','4'] 这样的数组,但我仍然需要将它们转换为十进制数并对它们求和。 有什么不太复杂的方法吗?

非常感谢您!祝大家编码愉快:)

写一个 stored procedure 来完成工作:

CREATE FUNCTION SPLIT_AND_SUM ( s VARCHAR(1024) ) RETURNS INT
BEGIN
   ...
END

PySpark 解决方案

from pyspark.sql.functions import udf,col,split
from pyspark.sql.types import FloatType 
#UDF to sum the split values returning none when non numeric values exist in the string
#Change the implementation of the function as needed
def values_sum(split_list):
    total = 0
    for num in split_list:
        try:
            total += float(num)
        except ValueError:
            return None
    return total

values_summed = udf(values_sum,FloatType())
res = df.withColumn('summed',values_summed(split(col('values'),';')))
res.show()

如果已知数组值属于给定数据类型,则解决方案可能是单行的。但是,最好采用涵盖所有情况的更安全的实施方式。

蜂巢解决方案

使用 explodesplitgroup by 对值求和。

select id,sum(cast(split_value as float)) as summed
from tbl
lateral view explode(split(values,';')) t as split_value
group by id

来自Spark-2.4+

我们不必在数组上使用 explode,而是直接在数组上使用 higher order functions

Example:

from pyspark.sql.functions import *

df=spark.createDataFrame([("1","2;4;4"),("2","5;1"),("3","8;0;4")],["id","values"])

#split and creating array<int> column
df1=df.withColumn("arr",split(col("values"),";").cast("array<int>"))

df1.createOrReplaceTempView("tmp")

spark.sql("select *,aggregate(arr,0,(x,y) -> x + y) as sum from tmp").drop("arr").show()
#+---+------+---+
#| id|values|sum|
#+---+------+---+
#|  1| 2;4;4| 10|
#|  2|   5;1|  6|
#|  3| 8;0;4| 12|
#+---+------+---+

#in dataframe API

df1.selectExpr("*","aggregate(arr,0,(x,y) -> x + y) as sum").drop("arr").show()
#+---+------+---+
#| id|values|sum|
#+---+------+---+
#|  1| 2;4;4| 10|
#|  2|   5;1|  6|
#|  3| 8;0;4| 12|
#+---+------+---+