我有一个包含多个数字列的大型表(站点) - 例如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
答案 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
语句来处理此情况。