有的业务需求需要联合使用多张事实表才能实现,这时通常会出现直接或间接多对多的连接情况,而多对多是必然会出现数据发散现象的。下面以 UserSkills、UserLanguages 以及 Users 三张表来演示间接的多对多情况:

假如有业务需求:①从会Python的员工中找出English最好的那个;②所有会Python的员工的平均English评分多少。这两个需求都同时涉及到两张表的数据,直接对两张表进行连接会出现度量数据的发散,再进行聚合很容易得到错误的数据结果(尤其是第二个需求):


对于记录数分别为 m 和 n 的两张多对多关系的表,连接后的结果表记录数会在
min(m,n)和m*n之间;三张表同理可知在min(n1,n2,n3)和n1*n2*n3之间。
有经验的技术人员可能会采用SQL的EXISTS语句这种过滤手段(或叫半连接,semi-join)来避免连接的发散问题,从而可以得到正确的数据结果,比如第二个需求的SQL代码:
SELECT UserLanguages.User
,Users.UserName
,AVG(UserLanguages.LangRating) as avg_english_rating
FROM UserLanguages
LEFT JOIN Users
ON UserLanguages.User = Users.User
WHERE UserLanguages.Language = 'English'
AND EXISTS(SELECT 1
FROM UserSkills
WHERE Skill = 'Python' AND User = UserLanguages.User)
GROUP BY UserLanguages.User
Users.UserName;
USS 的解决方案
统一星型模式(USS)则完全不存在多对多的数据发散问题,因为其桥接表中只存在一对一和多对一的连接方式,以及UNION ALL的拼接方式,而UNION ALL也是天生对发散免疫。下面用连接的方式来演示 USS 的解决方案:
当然,最佳的方案永远是 USS 方案与具备关联(association)的BI工具的组合使用。(另见〖避免“风扇陷阱”(USS)〗)

现在来演示同样第二个需求的解决办法:在BI工具(这里以FineBI为例)中将桥接表(Bridge)与三张表连接得到上图的大宽表后,分析人员可在FineBI中创建如下组件:

值得一提的是,若数据模型采用关联的方式,(此例的)其组件写法也是一模一样的。
这样就成功得到了正确的计算结果,其中唯一的难点是添加人工计算字段“Python_flag”,然而也相比传统的SQL代码简单很多。

382

被折叠的 条评论
为什么被折叠?



