在事实表(维度建模的数据仓库)中的度量字段中,NULL 值通常映射为 0 的原因是什么?
4 回答
尽管您已经接受了另一个答案,但我想说使用 NULL 实际上是一个更好的选择,原因有几个。
第一个原因是,当 NULL 存在时,聚合返回“正确”答案(即用户倾向于期望的答案),但当您使用零时给出“错误”答案。考虑这两个查询中 AVG() 的结果:
-- with zero; gives 1.5
select SUM(measure), AVG(measure)
from
(
select 1.0 as 'measure'
union all
select 2.0
union all
select 3.0
union all
select 0
) dt
-- with null; gives 2
select SUM(measure), AVG(measure)
from
(
select 1.0 as 'measure'
union all
select 2.0
union all
select 3.0
union all
select null
) dt
如果我们假设这里的度量是“制造项目的天数”并且 NULL 表示仍在生产的项目,那么零给出了错误的答案。同样的推理也适用于 MIN() 和 MAX()。
第二个问题是,如果零是默认值,那么如何区分作为默认值的零和作为实际值的零?例如,考虑“以欧元为单位的运费”的度量,其中 NULL 表示客户自己取货,因此没有运费,而零表示订单是免费运送给客户的。在不完全改变数据含义的情况下,您不能使用零来替换 NULL。您显然可以争辩说,应该从其他维度(例如运输方式)明确区分,但这会增加报告和理解数据的复杂性。
这取决于您要建模的内容,但通常是为了避免执行聚合时出现并发症。NULL
在许多情况下,将其视为0
这些目的是有意义的。
例如,在NULL
给定时间段内有订单的客户。或者是有NULL
销售收入的销售人员(真丢脸!)。
如果您打算对事实列进行平均,则应使用 NULL 而不是 0。这是我唯一一次相信 NULLS 在 dwh 事实或维度上是可以的
如果事实值未知/迟到,则最好保留为 NULL。
诸如 MIN、MAX 之类的聚合函数在 NULLS 上工作,只是忽略它们
(为了记录,拉尔夫·金博尔的一位伙伴在我打算的课程中说过这句话)
with goodf as
(
select 1 x
union all
select null
union all
select 4
)
select sum(x) sumx,min(x) minx,max(x) maxx,avg(cast(x as float)) avgx
from goodf
with badf as
(
select 1 x
union all
select 0 /* unknown */
union all
select 4
)
select sum(x) sumx,min(x) minx,max(x) maxx,avg(cast(x as float)) avgx
from badf
在高于平均值的 badf 中,结果不正确,因为它使用未知值的零作为字面意义上的 0