mysql:在一行中多个列的平均值,忽略空值

Sai*_*Sai 5 mysql sql

我有一个大表(站点)有几个数字列 - 比如说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's并添加正确的加权平均值(假设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
Run Code Online (Sandbox Code Playgroud)

van*_*van 3

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)
           )
Run Code Online (Sandbox Code Playgroud)

您也可以在其他部分中使用COALESCE,但是当您具有正确的评级值时,这不会处理这种情况,0因为它将被排除在外。该WHERE子句避免了,但如果该条目没有评级,DivideByZero您可能需要额外的语句来处理这种情况。UPDATE