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

Mar*_*tin 9 sql database-design data-modeling invoice

我目前正在开展一个小项目,我需要在其中建模以下场景:

脚本

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

思考

我需要一些帮助来找出理想的模型,但我有一些想法.

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

模型

这是我的数据模型v.1.0,请让我知道你的想法.

数据模型v.1.0 关注

然而,我对这个模型有一些关注:

  1. 草稿/报价/发票可能在订单行上有不同的商品和价格.在此模型中,所有草稿/报价/发票都连接到相同的订单和订单行,从而无法使用单独的报价行/草稿行/发票行.也许我会为此制作新表,但基本上相同的信息将存储在多个表中,这也不好.
  2. 有时两个或多个报价成为发票,这个模型将如何处理这个问题?

如果您有关于如何更好地建模的提示,请告诉我们!

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

No'*_*man 6

应该有一个表"quotelines",它类似于"orderlines".同样,你应该有一个'invoicelines'表.所有这些表格都应该有一个"价格"字段(名义上是该部分的默认价格)以及"折扣"字段.您还可以在"报价","订单"和"发票"表格中添加"折扣"字段,以处理现金折扣或特价优惠等事宜.尽管你写的是什么,这好事,有单独的表,因为在报价量和价格可能不适合客户实际订单,并再次它可能是不一样的金额,你实际上供应.

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

"行情","订单"和"发票"都应该有一个字段(外键),其中包含销售代表的价值; 此字段将指向不存在的"SalesRep"表.您还可以在"客户"表中添加"salesrep"字段,该字段指向客户的默认代表.此值将被复制到"引号"表中,但如果默认的不同代表给出引号,则可以更改该值.同样,当从报价单和订单发票订单时,应复制此字段.

我可以添加更多,但这一切都取决于你想要制作的系统的复杂性和详细程度.如果汽车根据其选项进行配置并相应定价,您可能需要添加某种形式的"物料清单".


Mik*_*ll' 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)
);
Run Code Online (Sandbox Code Playgroud)

我认为这对你所描述的模型有效,但我认为从长远来看,通过将这些模型建模为超类型/子类型,你会得到更好的服务.所有子类共有的列被"推"到超类型中; 每个子类型都有一个单独的表,用于该子类型的唯一属性.

这个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);
Run Code Online (Sandbox Code Playgroud)