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

时间:2010-03-15 08:17:30

标签: sql mysql

我有一个包含多个数字列的大型表(站点) - 例如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

1 个答案:

答案 0 :(得分: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)
           )

您也可以在其他部分使用COALESCE,但如果您的评分值0正确,则无法处理此情况,因为它将被排除。 WHERE子句避免使用DivideByZero,但如果条目没有评级,则可能需要额外的UPDATE语句来处理此情况。