MySQL中是否存在可计算列值乘积的聚合函数
MySQL 列值聚合乘积实现方案
MySQL 本身没有内置 product() 聚合函数,直接调用必然会抛出函数不存在的错误。要实现和 sum(column1)、avg(column1) 用法一致的列值乘积聚合能力,可根据自身场景选择以下方案:
对数转换方案(无需额外权限,性能高,适配绝大多数场景)
利用对数运算性质:乘积的对数等于各值对数的和,求和后取指数即可还原乘积结果,写法和内置聚合函数完全一致:全表计算乘积
SELECT EXP(SUM(LN(column1))) AS product_res FROM 你的表名;按分组计算乘积
SELECT 分组列, EXP(SUM(LN(column1))) AS product_res FROM 你的表名 GROUP BY 分组列;注意事项:
- 基础写法仅支持列值全为正数的场景,如果需要兼容0值、负数,可以调整写法增加符号和零值判断:
SELECT 分组列, IF( SUM(column1 = 0) > 0, 0, EXP(SUM(LN(ABS(column1)))) * IF(MOD(SUM(column1 < 0), 2) = 1, -1, 1) ) AS product_res FROM 你的表名 GROUP BY 分组列;
- 浮点数运算存在可忽略的微小精度误差,对精度要求为绝对精确的金融类场景不推荐使用
- 自定义聚合函数方案(用法和原生函数完全一致,无精度问题)
如果你的数据库账号有创建自定义函数的权限(需要SUPER权限,部分云托管MySQL可能限制该能力),可以直接创建一个原生支持聚合逻辑的PRODUCT函数,创建后就能按照你最初的预期直接调用:
先执行函数创建语句:
DELIMITER // CREATE AGGREGATE FUNCTION PRODUCT(calc_val DECIMAL(32,8)) RETURNS DECIMAL(32,8) DETERMINISTIC BEGIN DECLARE res DECIMAL(32,8) DEFAULT 1; DECLARE CONTINUE HANDLER FOR NOT FOUND RETURN res; calc_loop: LOOP FETCH NEXT FROM group_rows INTO calc_val; IF calc_val IS NULL THEN ITERATE calc_loop; END IF; SET res = res * calc_val; END LOOP; END // DELIMITER ;
创建完成后,直接调用即可,和sum()用法没有区别:SELECT PRODUCT(column1) FROM 你的表名 GROUP BY 分组列;
注意事项:
- 可以根据自身业务的数值大小、精度要求,调整语句中
DECIMAL的长度和小数位数参数,避免乘积溢出 - 该方案默认自动忽略NULL值,和
sum()、avg()对NULL的处理逻辑完全一致
内容的提问来源于stack exchange,提问作者KMarto
相关产品推荐
相关产品推荐

