[英]mysql: Average over multiple columns in one row, ignoring nulls
我有一个大表(站点)有几个数字列 - 比如说a到f。 (这些是来自不同组织的网站排名,例如alexa,google,quantcast等。每个都有不同的范围和格式;它们是来自外部数据库的直接转储。)
对于许多记录,这些列中的一个或多个为空,因为外部DB没有数据。 它们都涵盖了我的数据库的不同子集。
我希望列t是它们的加权平均值(每个a..f都有我赋予的静态权重),忽略空值(可以出现在任何一个中),除非它们全部为空,否则为null。
我更喜欢用简单的SQL计算来做这件事,而不是在应用程序代码中使用它,或者使用一些巨大的丑陋嵌套if块来处理每个空值的排列。 (鉴于我添加了更多的外部数据库源,我的平均列数越来越多,这将是指数级更难看和容易出错的。)
我会使用AVG,但这仅适用于分组,而且这是一个记录中的w /。 数据在语义上可以为空,我不想平均一些“平均”值代替空值; 我想只计算数据所在的列。
有没有办法做到这一点?
理想情况下,我想要的是像UPDATE sites SET t = AVG(a*@a_weight,b*@b_weight,...)
,其中任何空值都被忽略并且没有发生分组。
编辑:我最终使用的是基于van并添加正确的加权平均值(假设a
已根据需要进行了规范化,在本例中为0-1(1 =更好):
UPDATE sites
SET t = (@a_weight * IFNULL(a, 0) + ...) / (IF(a IS NULL, 0, @a_weight) + ...)
WHERE (IF(a IS NULL, 0, 1) + ...) > 0
UPDATE sites
--// TODO: you might need to round it depending on your type
SET t =(COALESCE(a, 0) +
COALESCE(b, 0) +
COALESCE(c, 0) +
COALESCE(d, 0) +
COALESCE(e, 0) +
COALESCE(f, 0)
) /
((CASE WHEN a IS NULL THEN 0 ELSE 1 END CASE) +
(CASE WHEN b IS NULL THEN 0 ELSE 1 END CASE) +
(CASE WHEN c IS NULL THEN 0 ELSE 1 END CASE) +
(CASE WHEN d IS NULL THEN 0 ELSE 1 END CASE) +
(CASE WHEN e IS NULL THEN 0 ELSE 1 END CASE) +
(CASE WHEN f IS NULL THEN 0 ELSE 1 END CASE)
)
WHERE 0<>((CASE WHEN a IS NULL THEN 0 ELSE 1 END CASE) +
(CASE WHEN b IS NULL THEN 0 ELSE 1 END CASE) +
(CASE WHEN c IS NULL THEN 0 ELSE 1 END CASE) +
(CASE WHEN d IS NULL THEN 0 ELSE 1 END CASE) +
(CASE WHEN e IS NULL THEN 0 ELSE 1 END CASE) +
(CASE WHEN f IS NULL THEN 0 ELSE 1 END CASE)
)
您也可以在其他部分使用COALESCE
,但是当您的值为0
时,这将无法处理,因为它将被排除。 WHERE
子句避免使用DivideByZero
,但如果条目没有评级,则可能需要有额外的UPDATE
语句来处理这种情况。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.