2010-06-02 76 views
3

嗨我正在开发一个发票应用程序。发票和发票行:您如何存储客户地址信息?

所以总的想法是有两个表:

发票(ID,日期,CustomerAddress,CustomerState,CustomerCountry,增值税,合计); InvoiceLine(Invoice_ID,ID,Concept,Units,PricePerUnit,Total);

正如你所看到的,这个基本的设计会导致很多记录的重复,客户端将拥有相同的地址,州和国家。

因此,替代方法是有一个地址表,然后建立关系地址<-发票。

但是,我认为发票是不可变的文件,应该按照它最初制定的方式存储。有时客户会更改他们的地址或状态,以及是否来自地址目录,这些地址目录会更改所有先前制作的发票。

那么你有什么经验?

客户地址如何存储在发票中?在发票表中?地址表?或者是其他东西?

您能提供指向书籍,文章或文档的指针吗?

回答

7

我强烈建议不要在发票中存储任何客户详细信息。

相反,我会像一个结构:

Customer表,用ID的主键

客户地址表中(因为每个客户可能有一段时间不同的地址),与客户id作为外键

发票表,地址字段是客户地址表的外键。

顺便说一句,我会考虑增加每行项目的增值税字段。有些国家对不同的物料类型有不同的增值税税率。

+0

您不觉得发票表几乎就像历史表一样,因此关于发票最初打印的信息的重复信息是否有效? – elviejo79 2010-06-02 00:43:40

+2

@elviejo,可以证明你是正确的,但你必须评估你是否想要一遍又一遍地存储相同的信息,或者只是将一个foriegn密钥存储到所使用的地址。如果您存储了foriegn密钥,那么它意味着一旦发票链接到它就不能更改旧地址,相反,任何更改都必须成为新的地址记录,并且只需在地址表上维护一个标志,以指示地址是否有效。 – slugster 2010-06-02 00:58:42

+1

@elviejo您也可以在不必为客户更改整个地址维护过程的情况下执行此操作。当订单成为发票时,您可以链接到一个客户实体和一个“匿名”地址实体(可能是账单到发货的角色),它们只包含发票时的地址。您查看所有地址栏并获取代理键。这个“地址”历史从不更新,只能插入。之前的地址只是重复使用。因此,您可以获得时间点数据,而无需改变您的整个客户维护设计。 – 2010-06-02 02:00:26

1

大多数标准的产品/订单数据库将有

a products table (ProductId, product info fields) 
a customers table (CustomerID, customer info like address etc) 
and an orders table (OrderNumber, CustomerID, date, etc) 

那么你的订单项目成为订单和产品之间的多对多的关系表。

orderItems (OrderNumber, ProductID, quantity, purchasePrice, vat, etc) 

要获得完整的发票,您需要查询订单表并将其与OrderItems表一起加入。 OrderItem通常具有购买价格等因为产品表中的价格可能会在创建订单后发生变化,并且该信息通常对于存储有用。

+1

虽然我同意你的一般设计,但过去我一直批评orderItems没有遵循标准化,因为你将在产品ID中拥有数千或数百万(Billions?)相同的信息,价格等。你如何解释这一点,或者这是一个正常化失败的例子吗? – JM4 2012-07-18 22:23:16

0

我认为这样做有三个表:Customer,InvoiceAddress,但它的构造,使一旦输入地址,它永远不会更新或删除,只有弃用。您的地址表中可以有一个IsDeprecatedIsActive布尔型字段。然后,当您创建发票时,发票链接到客户ID和当时正在使用的地址ID。当客户更改其地址时,将使用新的AddressID创建一个新记录,并用布尔字段废弃旧记录。或者,如果你真的想保持良好的记录和/或将永远需要查看这些数据,你可以有一个AddressActiveStartDateAddressActiveEndDate,但这会使查询更复杂一点。

这样,您仍旧保存旧地址,并且仍然与客户链接以供参考,同时还允许客户拥有多个列出的地址(例如一个用于装运,一个用于开票)。

您可以根据需要添加更多表格,例如Product,InvoiceLineState