10

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

设想

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

想法

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

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

模型

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

数据模型 v.1.0 关注点

然而,我对这个模型有一些担忧:

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

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

编辑:数据模型 v.1.4 在此处输入图像描述

4

3 回答 3

6

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

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

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

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

于 2011-04-17T10:36:17.013 回答
6

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

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)
);

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

这个 SO 问题及其接受的答案(和评论)说明了博客评论的超类型/子类型设计。另一个问题与个人和组织有关。还有一个与人员配备和电话号码有关。

之后 。. .

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

-- "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);
于 2011-04-17T11:34:59.443 回答
0

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

当 quote_line 变成 order_line 时,设置位从 0 到 3 再到 1。

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

卡德。

于 2020-01-29T14:41:41.780 回答