如果数据建模师不注意,如果数据模型没有通过适当的数据基数检查和平衡来处理,数据分析师就会遭受鸿沟和扇形陷阱的打击。
我们知道什么是数据建模。我们知道什么是数据基数。现在,是时候了解笛卡尔数据了,当财务部门手动知道总额为100,000美元,但运行查询时却看到200,000美元时,这会让他们感到无法摆脱的恐惧。
笛卡尔数据是关于在具有多对多(M:N)关系的表上编写查询的。
如果有两个具有“多对多”关系的表,那么数据建模师就需要引入一个中介表,该表可以具有唯一记录,然后可以与之前使用的两个表具有“一对多”关系。
如果销售表直接基于员工ID与目标表连接,那么肯定会有笛卡尔数据,因为销售表和目标表都可以有多个员工ID。但是,请注意,即使有中间表,如果查询编写错误,数据分析师仍然可能遇到称为Chasm Trap的笛卡尔数据。
参考“鸿沟和扇形陷阱”主题中的同一个例子。假设在员工表中有一个名为John的员工。他有两个目标要实现,例如,
1) For Product 1 = Target USD 1M,
2) For Product 2 = Target USD 2M.
他总共完成了10笔销售交易,每笔交易约为1万美元,现在他已经达到了10万美元。如果我们通过查询提取10万美元的信息,并将这3个表连接在一个查询中,就会发生这种情况。
Ø查询将会连接员工表和目标表,并在内存中处理2行数据,即,
vRow1: John with Target of USD 1M for Product 1
vRow2: John with Target of USD 2M for Product 2
Ø现在,查询在内存中有2行要与销售表连接。现在,它将使用John作为键将这2个John与销售表连接,这就是将发生的事情。
vJohn [Product 1] will join with 10 rows in Sales and will generate 10 Rows.
vJohn [Product 2] will join with 10 rows in Sales and again will generate 10 Rows.
v因此,总共会生成20行,这是错误的,因为现在总目标达成将显示为20万美元,而不是10万美元,这是错误的。
Ø问题是笛卡尔结果。
现在让我们来研究如何解决这个问题。处理这种情况有两种方法。
1) 分别编写两个查询
2) 在一个查询中写两个子查询,并使用UNION ALL。
让我们选择第二种方法,并通过例子来理解。
ü第一次查询将连接员工表和目标表,并在内存中处理2行数据,
vRow1: John with Target of USD 1M for Product 1
vRow2: John with Target of USD 2M for Product 2
ü第二个查询将连接员工表与销售表,并在内存中处理10行数据,
vRow1: John with Sales of USD 10k for Product 1
vRow2: John with Sales of USD 10k for Product 2
v......
vRow10: John with Sales of USD 10k for Product 2
ü现在,使用UNION ALL连接这两个查询,你会看到12行。
ü正确结果。
我不会详细解释,但当你连接两个具有重复数据的表时,数据会自我复制,例如,部门表(Dept.)有2行员工ID,即该员工可能在公司期间在多个部门工作。假设第二个表是薪资表(Sal),并且假设该员工在该公司工作了1年,那么将有12行数据,即每个月1行。现在,当你连接部门表时。而且如果使用员工ID字段连接Dept表和Sal表,输出将会有24行,总薪资将是应有的两倍。因此,正确的做法是Dept表和Sal表都应该先与Employee表连接,因为Employee表总是具有唯一的员工行数。