我即将在星型模式中创建一个包含事实和维度的数据仓库。
我想回答的商业问题通常是:
我们在第一季度向居住在纽约的30-35岁女性销售了多少钱?
我们去年在类别服装上卖多少钱?
我在考虑一个日期维度,其粒度为一小时(指定年,月,日,小时,季度,日期名称,月份名称等) 我也在考虑产品维度和用户维度。
我想知道是否可以使用单个事实表来回答这些问题,或者是否适当创建多个事实表?我在考虑如下表:
FactSales
DimDate - fk到包含日期信息的表格(例如季度,星期几,年,月,日)
DimProduct - fk到包含产品信息的表,例如(产品名称)
DimUser - fk到包含用户信息的表格,如(年龄,性别)
TotalSales - 这些特定日期,产品和用户的所有销售额的总和。
另外,如果我想测量摊位的总销售额(金钱)和销售总数?创建一个具有相同尺寸但使用TotalNumberOfSales作为事实的新事实表是否合适?
感谢我能得到的所有输入。
答案 0 :(得分:3)
我认为你走在正确的轨道上。上述所有问题都应该只使用一个覆盖销售的事实表来回答。
我认为应该开始一个非聚合,而是在需要时稍后聚合。考虑到一次销售可以包含多个产品和多个商品,我会按如下方式组织它...销售中每个产品的一个事实行(通常是发票上的行,所以我称之为“订单行”或“销售线“),也许三个柜台属性:
NumItems
- 项目数量,即如果客户购买三件相同产品,则为3件。NumLines
- “订单行”的数量 - 应该始终为1.在以后聚合数据时可能很有用(大赢在SQL中已经有sum(NumLines)
而不是count(*)
,或添加更正项目(NumLines = -1
)。NumSales
- 一个小数,因此可以总计得出销售数量(如果销售涉及三种不同的产品,则包含三个订单行,则为0.333)。现在,人们会得到一个问题,以获得正确的数量,即“涉及黑色衣服的销售数量”。我在之前的工作场所遇到过这个问题 - 我确信必须存在一些“最佳实践”,我们或多或少通过在事实表中引入SaleID
(或TransactionID
)来结束做count(distinct SaleID)
。缺乏优雅,但有效。
在我们的设置中,我们有几个货币属性 - 最重要的是,一个用于收入(在支付销售物品的直接成本后剩下的收入)和一个用于营业额(客户支付的价格)项目)。销售税或增值税可能会增加更多复杂性。一个人可以只使用一个货币属性,然后将销售额分成事实表中的多行,但我想我宁愿在销售额事实表中推荐多个货币列。事实表中的所有内容都以“基础货币”(欧元,在我们的例子中)计算,然后我们有一个汇率维度来跟踪确切的金额。
我认为拥有包含一天中小时的日期维度是不合理的。在我之前的工作中,我把我的仓库保留在postgres中,而且我实际上管理得很好而没有日期维度 - 虽然日期维度被认为是“最佳商业实践”我发现在性能方面我们所有的目的都有更好的性能通过使用标准的postgres日期函数而不是在日期维度中拖动。我用它玩了很多,我想最终我发现最优化的是将日期和时间分成两个不同的属性。 (时区和夏令时给了我一些额外的麻烦......)
答案 1 :(得分:2)
我同意Tobixen - 你正走在正确的轨道上。
我建议您阅读Ralph Kimball的书" The Data Warehouse Toolkit",特别是关于零售销售的章节 - 它深入探讨了销售事实。
日期维度就像拥有日历表一样 - 您可以根据季度,会计月份以及日期特定于业务的其他事项进行拆分。我通常同时保留日期键和时间戳数据类型,因此我们可以使用财务日历执行操作。如果你需要把你的桌子放在那个级别,用一天几小时的桶或者几分钟等,我实际上会有一个单独的时间维度。我怀疑你需要每小时一次。
这就是我要做的事情:
声明你的事实表的粒度:
每个订单行1行
请注意,谷物不包含任何不能唯一标识该行的内容。
订单行的维度属性:
Date
Time (if needed, and bucketed by hour/minute etc)
Product
Customer
订单行的退化维度(这些是与交易相关的代码):
Order Number
Order Line Number
一些示例措施:
Item Price at time of Sale (optional, may be useful in some situations)
Discount Amount
Sale Dollars
这应该回答所有这些问题。
对于总计,过滤维度属性后的简单COUNT / SUM应该可以正常工作。
你应该考虑到客户维度是最难建立的模型之一,Kimball在他的书中将整整一章用于客户维度。