说我有2件“我可以卖的东西”:service
和product
。每个表都有一个表格,用于捕获其独特属性(例如,服务可能具有每小时费率,而产品可能具有每单位价格等)。
每次销售时,假设我需要捕获有关销售的完全相同的数据,无论服务或产品是否已售出。我该如何建模?
方法1:
所以,像这样:
TABLE: product
- product_id (PK)
TABLE: service
- service_id (PK)
TABLE: sale
- sale_id (PK)
TABLE: product_sale
- product_id (FK)
- sale_id (FK)
TABLE: service_sale
- service_id (FK)
- sale_id (FK)
方法2:
跳过映射表,只有单独的表来记录产品和服务的销售情况。
TABLE: product
- product_id (PK)
TABLE: service
- service_id (PK)
TABLE: product_sale
- product_sale_id (PK)
- product_id (FK)
TABLE: service_sale
- service_sale_id (PK)
- service_id (FK)
我认为方法1会更好,因为我需要生成以下报告:
答案 0 :(得分:7)
由于您列出的原因,您的方法1比方法2更优惠。能够在任何类型的所有销售中收集数据并在一次销售中拥有多个项目。方法2表明,产品和服务一次只能销售1个,而不是捆绑在一起。但我不得不想知道你为什么要首先将产品和服务分开? (根据您的需要,这将是行业特定的)。大多数电子商务系统和小型企业会计系统使用更简单的模型和一个产品表。
所以这是我使用一个产品表对您的问题的正式回答:
所以你在这个简单的例子中有三个表:
这是大多数现成的电子商务系统和小型企业会计系统的工作方式。
如果您需要超级特定的跟踪,您肯定会变得更复杂,但您需要通过解释为什么单位模式的价格不适用于您的用例来证明成本和复杂性。 (汽车经销商是一个例子,服务的跟踪方式与正常情况完全不同,服务/产品在单独的表格中都与订单项相关联,这些订单项代表关于您汽车的一个“问题”或“投诉”。每个订单项都包含产品组件和服务组件。)
更新:@Doug指出,我的原始答案显得不够清楚。为销售创建发票时,当前PricePerUnit将与QuantitySold字段以及对产品主数据快照重要的任何其他数据一起复制到InvoiceLineItem记录,以防您需要撤消事务。即使产品价格在未来发生变化,这也可确保发票始终保持相同的总额。它还允许您在客户退货时撤消发票,并确保客户获得的金额与付款相同,无论当前价格如何。
答案 1 :(得分:5)
实际上,我的方式不同:
TABLE: salable
- salable_id (PK)
- price (per unit)
- unit ("hour", "kilogram", "part", "unit")
- description
TABLE: product
- salable_id (FK)
- manufacturer
- units_in_stock
TABLE: service
- salable_id (FK)
- provider
TABLE: sale
- sale_id (PK)
- salable_id (FK)
- units
- total
关键是"可销售"摘要服务和产品共有的东西。在您的情况下,这可能不是理想的解决方案,但这是其他人尚未提及的可行设计。
附录:为了确保准确记录,大多数受尊敬的销售/财务系统将为每个销售的每个行项目拍摄每个产品/服务记录的快照。由于我们应该为每次销售无论如何拍摄我们的产品记录快照,因此所有可售商品都可以更简单,更直接地分享一组核心字段。
答案 2 :(得分:1)
方法1最适合您的目的。它也更适合构建在数据库层之上的中间件层 - 您可以轻松地将ORM解决方案放在使用第一种方法建模的现有数据库结构上
答案 3 :(得分:0)
我这样做的次数不止一次:
表产品: - product_id(PK) - 描述 - product_type_id(FK)
表发票:
表invoice_line: - invoice_id - product_id - product_type_id - 价格
表product_type - product_type_id - 说明
所以,在你的最后一张桌子上,设置两个itens:1 - “product”,2 - “service” 产品将被创建为“1”,“香蕉”,“1”(它是产品); 将创建服务,如“2”,“换油”,“2”(这是一项服务);
现在,在创建发票时,请确保将所选产品的product_type_id传递到invoice_line表。这将在查询“SELECT * from invoce_line WHERE product_type_id = 2”等数据时获得更多性能 - 获取销售服务的所有数据。 (1代表产品)。
因此,您将所有发票数据保存在一个唯一的表格中;例如,您可以通过简单的连接查询获取所有客户端的服务,例如(client_id将为10):
Select * from invoice_line
join invoice
on invoice_line.invoice_id = invoice.invoice_id and client_id = 10
where product_type_id = 2
这几乎可以解决所有问题。我有1000多人在这样的事情上工作,直到今天,没有任何缺陷。
希望它有所帮助。
答案 4 :(得分:0)
如果您尝试规范化数据库,第一种方法是有利的。在这种情况下,您可以将sale
实体的属性与sale_id = xx重复用于其他产品。如果您每次销售(销售交易)销售多种产品/服务,则需要复制销售属性。
可以使用索引策略/分区来解决按人/日期范围查询的问题。如果你知道你的数据会快速增长......那么这将是另一个关于DW项目的问题。
希望它有所帮助。
答案 5 :(得分:0)
在撰写本文时,我相信答案忽略了一件事:
当某物的价格发生变化时会发生什么?
我提出这个问题是因为你特别提到了报道。
以前的所有销售现在都显示新价格吗?所有服务都以相同的费率收费(或者某些客户可以获得折扣吗?)
我认为你的“销售”领域概念需要包含纯粹价值对象的“已售商品”。
这可能无关紧要 - 但你必须做出类似的决定。这就是领域模型获得大量挥手的原因。
所以我建议选项1,但考虑到产品/服务销售表应该引用sold_product和sold_service而不是'origin'产品/服务。