【问题标题】:How to get average values from dictionary looking values using SQL?如何使用 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 列的值也可以是

标签: mysql sql presto


【解决方案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 可以提供帮助
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-14
    • 1970-01-01
    • 1970-01-01
    • 2023-02-23
    相关资源
    最近更新 更多