在我的应用程序中,我有一个Customer
类和一个Address
类。 Customer
类有Address
类的三个实例:customerAddress
,deliveryAddress
,invoiceAddress
。
什么是在数据库中反映此结构的最佳方式?
你有什么经历?这些方法有什么优点和缺点吗?
答案 0 :(得分:11)
如果您100%确定客户将只拥有您描述的3个地址,那么这是可以的:
CREATE TABLE Customer
(
ID int not null IDENTITY(1,1) PRIMARY KEY,
Name varchar(60) not null,
customerAddress int not null
CONSTRAINT FK_Address1_AddressID FOREIGN KEY References Address(ID),
deliveryAddress int null
CONSTRAINT FK_Address2_AddressID FOREIGN KEY References Address(ID),
invoiceAddress int null
CONSTRAINT FK_Address3_AddressID FOREIGN KEY References Address(ID),
-- etc
)
CREATE TABLE Address
(
ID int not null IDENTITY(1,1) PRIMARY KEY,
Street varchar(120) not null
-- etc
)
否则我会像这样建模:
CREATE TABLE Customer
(
ID int not null IDENTITY(1,1) PRIMARY KEY,
Name varchar(60) not null
-- etc
)
CREATE TABLE Address
(
ID int not null IDENTITY(1,1) PRIMARY KEY,
CustomerID int not null
CONSTRAINT FK_Customer_CustomerID FOREIGN KEY References Customer(ID),
Street varchar(120) not null,
AddressType int not null
-- etc
)
答案 1 :(得分:5)
我会(就像数据库理论教导的那样)选择两个独立的表:客户和地址。
正如您所说,将三个字段放在Customer表中的想法很糟糕,因为它会违反规范化规则(并且当地址变为三个以上时会失败)。
编辑:另外,我将地址表记录分成几个字段,一个用于地名前缀,一个用于街道等,并在其中放置一个唯一的密钥。否则,你将以一个装满重复数据库的数据库结束。
答案 2 :(得分:4)
我会去非规范化。这更容易。
如果对其进行规范化,则地址表将要求您删除重复项并重新链接客户表中的记录。如果我有相同的交货和发票地址,它似乎应该链接到同一记录。如果我换一个,你需要:
如果我将其更改回来,您需要检查:
这种编程开销似乎消除了规范化似乎提供的更少空间的优势。像你指出的那样,非规范化解决方案可以提供更快的查询和更容易的维护(编程方式)。这似乎是我的决定性因素。
如上所述,规范化解决方案将允许您稍后添加更多地址。但是你必须为外键添加一个字段,除非你计划组织表而没有从客户到地址表的链接。
规范化的优点
非规范化的优点
答案 3 :(得分:4)
使用2个表,Customer,Address。
在地址表中创建地址后,通常不允许修改地址(可能是修正拼写错误的特定工具)。 IOW使地址的ID与地址本身一致。
您现在可以在任何地方引用这些地址表条目。例如,当订单被分派给客户时,订单表引用的地址ID可以与客户表中的DeliveryAddressID字段中的地址ID相同。
如果客户希望将当前的文件传递地址更改为新地址,则会创建新的地址记录。历史交货数据不受此影响,但新订单会自动使用新地址。
注意这在缓存Addresss对象时也很有用(它们是不可变的并且对于长期缓存是安全的),它们可以分发并且更容易测试是否相等(通过ID属性)。
答案 4 :(得分:2)
我在Zen Cart中也有这个(也可能是osCommerce),在订单表中,想知道为什么他们这样做,甚至更多,因为他们有一个地址表。
我看到的唯一有效的原因是出于记录目的:即使客户更改了地址,订单信息也不得更改,它会反映订单时的数据。
现在,如果同一个客户做了很多订单,那就有点浪费了。一种可能的解决方案是保留地址历史记录并将其与订单一起引用 我想知道这些不可变的地址(或者如果它们还没有相关的订单可变的话)应保存在常规地址簿中或单独的历史表中,仅在订单生成时填写(如果同一客户保留,则避免重复)当然是相同的地址。) 前者的优点是避免使用两个非常相似的结构和重复信息的表,但随着历史的增长可能会阻碍性能(?)。虽然人们在实践中很少改变这些信息 后者具有分离角色的优势(一个是不可变的,而不是另一个),历史很少使用。
总的来说,如果您的应用程序不需要保留历史记录,只需选择两个单独的表。
答案 5 :(得分:2)
在这种情况下,将每个地址字段放在不同的行中不是标准化。它只是表分区。假设任何具有更多表的模式“更加规范化”都是错误的。
假设我们在数据库中有这两种替代模式: 1)user:user_id,username,password
2)user:user_id,password_id 密码:password_id,密码
(2)是否比(1)“更规范”? 否!
在这个OP的情况下,只要: 1)我们将地址视为原子价值, 2)应用程序只需要这三种类型的地址。
然后将每个地址存储在不同的列中同样有效。第二种解决方案不会将地址分解为其组件(国家,城镇,街道等)。因此它不比第一个更“规范化”!
答案 6 :(得分:1)
如果你有令人信服的理由,我的两分钱就是你所描述的方式正常化 OK 。有时,这个原因可以像高度自信一样简单,你永远不需要规范化的形式。正如Stefan Mai暗示的那样,如果您只需要使用您指定的三种类型的地址,那么只检索和更新单个表会更容易。另一方面,如果三个地址要求有可能发生变化那么它可能会发生变化,而且早期就是规范化的最佳时机。