数据建模草稿/报价/订单/发票

Posted

技术标签:

【中文标题】数据建模草稿/报价/订单/发票【英文标题】:Data modelling draft/quote/order/invoice 【发布时间】:2011-08-07 06:25:20 【问题描述】:

我目前正在做一个小项目,我需要对以下场景进行建模:

场景

    客户来电,他想要一辆新车的报价。 销售代表。注册客户信息。 销售代表。在系统中创建报价,并将项目添加到报价(汽车)中。 销售代表。通过电子邮件将报价发送给客户。 客户接受报价,现在报价不再是报价而是订单。 销售代表。检查订单,一切正常,他为订单开具发票。该订单现在不再是订单,而是发票。

想法

我需要一些帮助来找出理想的建模方法,但我有一些想法。

    我认为草稿/报价/发票基本上都是一个订单。 草稿/报价/发票需要单独的唯一编号(ID),所以我正在考虑为所有这些单独的表格。

型号

这是我的数据模型 v.1.0,请告诉我你的想法。

关注

不过,我对这个模型有些担心:

    草稿/报价单/发票在订单行上可能有不同的项目和价格。在此模型中,所有草稿/报价/发票都连接到同一订单和订单行,因此不可能有单独的报价行/草稿行/发票行。也许我会为此制作新表,但是基本上相同的信息会存储在多个表中,这也不好。 有时两个或多个报价会变成发票,该模型将如何处理这个问题?

如果您对如何更好地建模有任何提示,请告诉我!

编辑:数据模型 v.1.4

【问题讨论】:

所有子类型共有的列应该向上移动到超类型中。如果每个子类型都有一个 subtype_date 列,它可能应该移到超类型中。 (删除 quote_date、order_date、invo_date;只需使用 stmt_date。)对于 subtype_canceled 也是如此。 order_id 和 invo_id 列需要保留在它们的子类型中,因为您需要考虑每个 id 号。 (没有间隙。)引号也可能是这样。我不知道。 好的,我明白了。以为我误会了。我在子类型中添加 order_date 的原因是我希望报价/订单/发票日期彼此不同,我还认为所有报价/订单/发票的声明都是相同的。但是我看到,对于您制作的每份报价/发票/订单,您也会做出一份声明,对吗?但是当报价被接受并需要变成订单时会发生什么?我是否只是创建一个新订单并复制报价详细信息,以便旧报价和新订单都存在?是否也是两个陈述,每个陈述一个?我可以将 Q 与 I 联系起来吗? 如果您以这种方式构建表格,“statement”中的每一行都是报价单、发票或订单。当报价“变成”订单时,您在可更新视图“订单”中插入一行(请参阅下面的答案),然后复制报价行项目。 (您只需要一个订单项表格;我稍后会尝试发布。)如果订单项从未有任何更改 - 这是一个hard never --您可以使用不同的、更简单的结构。 (我经常看到类似“是的,我们为此报价 39.95 美元,但我们感谢您的业务,因此我们将免费提供”之类的内容。) 而且,是的,您可以将报价与发票相关联。只需将报价单号(我想还有订单号)存储在发票子类型中。 所以您认为我应该在 Invoice 表中为 Quote-/OrderID 添加一个字段?如果没有报价或订单相关,那么这些字段将是空白的怎么办?那是好的数据库设计吗? 【参考方案1】:

看起来您已经对这些事物中的每一个进行了建模——报价单、订单、草稿、发票——在结构上与所有其他事物相同。如果是这种情况,那么您可以将所有相似的属性“推送”到一个表中。

create table statement (
    stmt_id integer primary key,
    stmt_type char(1) not null check (stmt_type in ('d', 'q', 'o', 'i')),
    stmt_date date not null default current_date,
    customer_id integer not null  -- references customer (customer_id)
);

create table statement_line_items (
    stmt_id integer not null references statement (stmt_id),
    line_item_number integer not null,
    -- other columns for line items
    primary key (stmt_id, line_item_number)
);

我认为这适用于您所描述的模型,但我认为从长远来看,将它们建模为超类型/子类型会更好地为您服务。所有子类型共有的列被“向上”推入超类型;每个子类型都有一个单独的表,用于记录该子类型独有的属性。

This SO question 及其接受的答案(和 cmets)说明了博客 cmets 的超类型/子类型设计。 Another question 与个人和组织有关。 Yet another 与人员配备和电话号码有关。

稍后。 . .

这还不完整,但我没时间了。我知道它不包括订单项。可能漏掉了别的东西。

-- "Supertype". Comments appear above the column they apply to.
create table statement (
  -- Autoincrement or serial is ok here.
  stmt_id integer primary key,    
  stmt_type char(1) unique check (stmt_type in ('d','q','o','i')),
  -- Guarantees that only the order_st table can reference rows having
  -- stmt_type = 'o', only the invoice_st table can reference rows having
  -- stmt_type = 'i', etc.
  unique (stmt_id, stmt_type),
  stmt_date date not null default current_date,
  cust_id integer not null -- references customers (cust_id)
);

-- order "subtype"
create table order_st (
  stmt_id integer primary key,
  stmt_type char(1) not null default 'o' check (stmt_type = 'o'),
  -- Guarantees that this row references a row having stmt_type = 'o'
  -- in the table "statement".
  unique (stmt_id, stmt_type),
  -- Don't cascade deletes. Don't even allow deletes. Every order given
  -- an order number must be maintained for accountability, if not for
  -- accounting. 
  foreign key (stmt_id, stmt_type) references statement (stmt_id, stmt_type) 
    on delete restrict,
  -- Autoincrement or serial is *not* ok here, because they can have gaps. 
  -- Database must account for each order number.
  order_num integer not null,  
  is_canceled boolean not null 
    default FALSE
);

-- Write triggers, rules, whatever to make this view updatable.
-- You build one view per subtype, joining the supertype and the subtype.
-- Application code uses the updatable views, not the base tables.    
create view orders as 
select t1.stmt_id, t1.stmt_type, t1.stmt_date, t1.cust_id,
       t2.order_num, t2.is_canceled
from statement t1
inner join order_st t2 on (t1.stmt_id = t2.stmt_id);

【讨论】:

是的,我一开始就是这样,但后来我遇到了一个问题。我需要发票/草稿/报价单有单独的数字(ID)。订单和发票的编号系列需要与订单不同。 只是一个整数;你可以在里面放任何你想要的数字。如果您更改主键以使其成为(stmt_id,stmt_type),则可以为每种语句进行独立编号。但是你提出的问题正是超类型/子类型设计很好地解决的问题。订单号将进入实现子类型“订单”的表中;实现子类型“发票”的表格中的发票编号。 嗯.. 有道理。我已经更新了我的模型,请你看一下。 @Martin:我认为您需要再次阅读我链接的问题和答案。 @Catcall:我已经阅读了它们,我得到了它的插入部分。如果要创建报价,我在语句和报价表中添加一行。这很好,但我不能 100% 确定当报价变成订单/发票时,需要进行哪些操作?【参考方案2】:

应该有一个表格“quotelines”,类似于“orderlines”。同样,您应该有一个“invoicelines”表。所有这些表都应该有一个“价格”字段(名义上将是零件的默认价格)以及一个“折扣”字段。您还可以在“报价”、“订单”和“发票”表中添加“折扣”字段,以处理现金折扣或特别优惠等事项。尽管您写了些什么,但最好有单独的表格,因为报价中的数量和价格可能与客户实际订购的不符,而且它可能与您实际供应的数量不同.

我不确定“草稿”表是什么 - 您可以将“草稿”和“发票”表结合起来,因为它们包含相同的信息,其中一个字段包含发票的状态 - 草稿或最终。将发票数据与订单数据分开很重要,因为您可能会根据收入(发票)纳税。

“Quotes”、“Orders”和“Invoices”都应该有一个字段(外键)来保存销售代表的值;该字段将指向不存在的“SalesRep”表。您还可以在“客户”表中添加一个“销售代表”字段,该字段指向客户的默认代表。该值将被复制到“报价”表中,但如果与默认值不同的代表给出报价,则可以更改它。同样,当根据报价生成订单并根据订单生成发票时,应复制此字段。

我可能会添加更多内容,但这完全取决于您想要制作的系统的复杂程度和详细程度。如果汽车根据其选项进行配置并相应定价,您可能需要添加某种形式的“材料清单”。

【讨论】:

感谢您的cmets,我已经更新了我的数据模型,您现在可以看一下吗? 'Orders' 应该有一个指向 'quotes' 的链接,而不是相反。顺序应该是报价 -> 订单 -> 发票(我省略了草稿,因为我认为没有必要),其中每个表格都包含指向前一个表格的链接。【参考方案3】:

向 line_items 添加一个新列(例如:Status as smallint)

当 quote_line 变成 order_line 时,然后设置您从 0 到 3 到 1 选择的位。

但是当 qty 改变时,添加一个带有新 qte 的新行并保持最后一行不变。

卡德。

【讨论】:

以上是关于数据建模草稿/报价/订单/发票的主要内容,如果未能解决你的问题,请参考以下文章

SAP Cloud for Customer里Sales Order和Sales Quote的建模方式

数据仓库-订单管理应该注意那些事项?

sql [magento]为订单,报价单,发票,货件或贷项通知单设置下一个increment_id

05-数据仓库之建模实例

数学建模太难,如何以Tableau可视化的方式打开?

数学建模太难,如何以Tableau可视化的方式打开?