如何使用 SQL 从字典查找值中获取平均值?

Posted

技术标签:

【中文标题】如何使用 SQL 从字典查找值中获取平均值?【英文标题】:How to get average values from dictionary looking values using SQL? 【发布时间】:2021-12-24 23:58:39 【问题描述】:

我的数据框如下所示:

id            value
a       0:3,1:0,2:0,3:4
a       0:0,1:0,2:2,3:0
a       0:0,1:5,2:4,3:0

我想编写一个查询来获取列 value 中键的平均值?

例如对于0:3,1:0,2:0,3:4,它必须是(0+0+0+3+3+3+3)/7 = 1.71

对于0:0,1:0,2:2,3:0,它必须是(2+2)/2=2

对于0:0,1:5,2:4,3:0,它必须是(1+1+1+1+1+2+2+2+2)/9 = 1.44

所以想要的结果是:

id            value
a              1.71
a              2.00
a              1.44

如何做到这一点?有没有 sql 函数可以得到这个结果?

【问题讨论】:

我怀疑 SQL 可以做到这一点。您可以编写一个存储过程,但是对于这种操作,SQL 是一个糟糕的语言选择。最好/最容易在应用层完成。 select version(); 显示什么? 键的数量是可变的吗?如果有,最多可以有多少? 您将a 显示为所有行的ID;是否有主键或其他唯一约束? @ysth 是的,除了“a”之外,id 列的值也可以是 【参考方案1】:

看到这个DBFIDDLE

代码:

CREATE  PROCEDURE `avg_dict`(s varchar(100))
BEGIN
  SET @result = CONCAT('SELECT (', replace(replace(s, ":","*"),",","+"), ')/(',regexp_replace(s,",?[0-9]:","+"),')');
  PREPARE stmt FROM @result;
  EXECUTE stmt  ;
  DEALLOCATE PREPARE stmt;
END

结果:

stmt output
CALL avg_dict("0:3,1:0,2:0,3:4"); 1.1743
CALL avg_dict("0:0,1:0,2:2,3:0"); 2.0000
CALL avg_dict("0:0,1:5,2:4,3:0"); 1.4444

【讨论】:

【参考方案2】:

通过split's、transforms 和repeat 的某种组合,您可以实现您的目标:

WITH dataset(id, value) AS (
    values ('a', '0:3,1:0,2:0,3:4'),
        ('a', '0:0,1:0,2:2,3:0'),
        ('a', '0:0,1:5,2:4,3:0')
)

SELECT id,
    reduce(arr, 0.0, (s, x)->s + x, s->s) / cardinality(arr)
FROM(
        SELECT *,
            flatten(
                transform(
                    transform(
                        split(value, ','),
                        s->split(s, ':')
                    ),
                    arr->repeat(
                        cast(arr [ 1 ] as INTEGER),
                        cast(arr [ 2 ] as INTEGER)
                    )
                )
            ) as arr
        FROM dataset
    )

输出:

id _col1
a 1.7142857142857142
a 2.0
a 1.4444444444444444

注意:

外部选择可以替换为array_average,但我使用了他选择,因为 Athena 的 Presto 版本不支持它。

UPD

另一个性能更高的版本:

SELECT id,
    reduce(
        arr,
        CAST(ROW(0.0, 0) AS ROW(sum DOUBLE, count INTEGER)),
        (s, r)->CAST(
            ROW(r.num * r.count + s.sum, s.count + r.count) AS ROW(sum DOUBLE, count INTEGER)
        ),
        s->IF(s.count = 0, NULL, s.sum / s.count)
    )
FROM(
        SELECT *,
            transform(
                split(value, ','),
                s->CAST(
                    ROW(
                        CAST(split(s, ':') [ 1 ] AS DOUBLE),
                        (CAST(split(s, ':') [ 2 ] AS INTEGER))
                    ) AS ROW(num DOUBLE, count INTEGER)
                )
            ) as arr
        FROM dataset
    )

【讨论】:

thx,“外部选择可以替换为array_average”是什么意思?哪个部分可以替代? 它返回了一个错误 "PrestoQueryError(type=INTERNAL_ERROR, name=GENERIC_INTERNAL_ERROR, message="SignatureBinder.iterativeSolve 在 4 次迭代后不收敛。"" @skulldoger 通过外部选择我的意思是外部选择。即SELECT id, reduce(..) FROM() 可以被删除,内部选择更改为SELECT *, array_average(faltten(....)) @skulldoger 请查看更新。至于您的错误 - 也许this 可以提供帮助

以上是关于如何使用 SQL 从字典查找值中获取平均值?的主要内容,如果未能解决你的问题,请参考以下文章

从字典集合值中查找所有数据到另一个字典集合键

C# - 字典 - 如何在字典中获取特定类值的最大值? [复制]

MySQL JSON:如何从键值中查找对象

如何从字符串值中获取数字代码?

如何从其 String 值中查找 Java 枚举?

如何将嵌套字典列表与它们的值中的公共键相加? [复制]