如何使用 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、transform
s 和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 从字典查找值中获取平均值?的主要内容,如果未能解决你的问题,请参考以下文章