从概念上讲,尽管在您的业务环境中,“ 订单”和“ 地址”是紧密相关的想法,但实际上它们是两种不同的实体类型,每种类型都有其自己的一组适用属性(或属性)和约束。
因此,如先前在评论中所述,我同意@Erik,并且您应该组织数据库的逻辑布局,并声明其他元素:
- 一个离散表,用于保存地址信息;
- 一张表格,保留客户特定的详细信息;
- 一张表,其中包含订单数据点;和
- 一个包含有关客户和地址之间关联的事实的表格;
我将在下面举例说明。
信息库IDEF1X图表
一幅图片价值一千个单词,因此我创建了图1所示的IDEF1X图,以说明我的建议所带来的一些可能性:
客户,地址及其关联
如所示,我描绘了实体类型Customer a和Address之间的多对多(M:N)基数比的关联。这种方法将提供未来的灵活性,因为您知道,一个客户可以随着时间的推移,甚至同时保留多个地址,并且同一地址可以由多个客户共享。
一对多(1:M)客户可以多种方式使用特定地址;例如,可以将其定义为“ 实物”,和/或可以将其设置为“ 装运 ”和/或“ 结算”。也许同样的地址实例可以同时服务于每个上述目的,或者它可以覆盖两个用途而不同的地址发生覆盖剩余的一个。
一个在某些业务环境中,客户可以是个人或组织(情况这将意味着一个稍微不同的安排,详见在这个答案大约一个超型亚型结构),但与目标提供了一个简单的例子,我决定这里不包括这种可能性。万一您需要在数据库中解决这种情况,上一个链接的帖子显示了解决上述需求的方法。
订单,地址,客户地址和地址角色
通常,订单仅需要两种地址,一种用于装运,一种用于开票。这样,同一个Address实例可以填充单个Order的两个Role,但是每个Role由各自的属性(如ShippingAddressId或BillingAddressId)来描绘。
借助两个多属性FOREIGN KEY,通过CustomerAddress关联实体类型将订单与地址相连。
- (CustomerNumber,ShippingAddressId)和(CustomerNumber,BillingAddressId),
两者都指向显示为CustomerAddress的多属性PRIMARY KEY,如下所示
- (CustomerNumber,AddressId)
…有助于表示一个业务规则,该规则规定(a)订单实例必须与(b)先前与发出该订单的特定客户相关联的地址出现,而不是与(c)随机非客户 -相关地址。
(1)地址和(2)CustomerAddress关联的历史记录
如果要提供修改地址信息的可能性,则必须跟踪所有数据更改。通过这种方式,我将Address描述为维护其自身AddressHistory的“可审核”实体类型。
由于客户与地址之间的连接性质也可能遭受一个或多个修改,因此我也描述了借助CustomerAddressHistory实体类型将这种关联作为“可审核的”关联进行处理的可能性。
在这方面,问答中涉及的各种因素。1和问答编号 关于启用数据库中的临时功能的图2确实很重要。
说明性的SQL-DDL逻辑布局
因此,根据上面显示和解释的图,我声明了以下逻辑级别的安排(您可以根据需要正确地调整以满足您的需求):
-- You should determine which are the most fitting
-- data types and sizes for all your table columns
-- depending on your business context characteristics.
-- Also, you should make accurate tests to define the
-- most convenient INDEX strategies based on the exact
-- data manipulation tendencies of your business domain.
-- As one would expect, you are free to utilize
-- your preferred (or required) naming conventions.
CREATE TABLE Customer (
CustomerNumber INT NOT NULL,
SpecificAttribute CHAR(30) NOT NULL,
ParticularAttribute CHAR(30) NOT NULL,
CreatedDateTime DATETIME NOT NULL,
--
CONSTRAINT Customer_PK PRIMARY KEY (CustomerNumber)
);
CREATE TABLE Address (
AddressId INT NOT NULL,
SpecificAttribute CHAR(30) NOT NULL,
ParticularAttribute CHAR(30) NOT NULL,
CreatedDateTime DATETIME NOT NULL,
--
CONSTRAINT Address_PK PRIMARY KEY (AddressId)
);
CREATE TABLE CustomerAddress (
CustomerNumber INT NOT NULL,
AddressId INT NOT NULL,
IsPhysical BIT NOT NULL,
IsShipping BIT NOT NULL,
IsBilling BIT NOT NULL,
IsActive BIT NOT NULL,
CreatedDateTime DATETIME NOT NULL,
--
CONSTRAINT CustomerAddress_PK PRIMARY KEY (CustomerNumber, AddressId),
CONSTRAINT CustomerAddressToCustomer_FK FOREIGN KEY (CustomerNumber)
REFERENCES Customer (CustomerNumber),
CONSTRAINT CustomerAddressToAddress_FK FOREIGN KEY (AddressId)
REFERENCES Address (AddressId)
);
CREATE TABLE MyOrder (
CustomerNumber INT NOT NULL,
OrderNumber INT NOT NULL,
ShippingAddressId INT NOT NULL,
BillingAddressId INT NOT NULL,
SpecificAttribute CHAR(30) NOT NULL,
ParticularAttribute CHAR(30) NOT NULL,
OrderDate DATE NOT NULL,
CreatedDateTime DATETIME NOT NULL,
--
CONSTRAINT Order_PK PRIMARY KEY (CustomerNumber, OrderNumber),
CONSTRAINT OrderToCustomer_FK FOREIGN KEY (CustomerNumber)
REFERENCES Customer (CustomerNumber),
CONSTRAINT OrderToShippingAddress_FK FOREIGN KEY (CustomerNumber, ShippingAddressId)
REFERENCES CustomerAddress (CustomerNumber, AddressId),
CONSTRAINT OrderToBillingAddress_FK FOREIGN KEY (CustomerNumber, BillingAddressId)
REFERENCES CustomerAddress (CustomerNumber, AddressId)
);
CREATE TABLE AddressHistory (
AddressId INT NOT NULL,
AuditedDateTime DATETIME NOT NULL,
SpecificAttribute CHAR(30) NOT NULL,
ParticularAttribute CHAR(30) NOT NULL,
CreatedDateTime DATETIME NOT NULL,
--
CONSTRAINT AddressHistory_PK PRIMARY KEY (AddressId, AuditedDateTime),
CONSTRAINT AddressHistoryToAddress_FK FOREIGN KEY (AddressId)
REFERENCES Address (AddressId)
);
CREATE TABLE CustomerAddressHistory (
CustomerNumber INT NOT NULL,
AddressId INT NOT NULL,
AuditedDateTime DATETIME NOT NULL,
IsPhysical BIT NOT NULL,
IsShipping BIT NOT NULL,
IsBilling BIT NOT NULL,
IsActive BIT NOT NULL,
CreatedDateTime DATETIME NOT NULL,
--
CONSTRAINT CustomerAddressHistory_PK PRIMARY KEY (CustomerNumber, AddressId, AuditedDateTime),
CONSTRAINT CustomerAddressHistoryToCustomerAddress_FK FOREIGN KEY (CustomerNumber, AddressId)
REFERENCES CustomerAddress (CustomerNumber, AddressId)
);
如果您想看看,我在运行于SQL Server 2017的db <>小提琴中对其进行了测试。
该History
表
您的问题的以下摘录非常重要:
我要寻找的是如何设置地址,以便在编辑地址时,订单不受客户更新其地址或重新安置的事实的影响。
该AddressHistory
和CustomerAddressHistory
在确保一台辅助订单不受地址的变化,所有的“以前”行应在各自保留History
表,可查询时需要。应该禁止在这两个表上执行UPDATE和DELETE操作(试图更改历史记录甚至会产生负面的法律影响)。
在其中包含的值之间的间隔AddressHistory.CreatedDateTime
,AddressHistory.AuditedDateTime
代表整个期间,在此期间,某个“过去” Address
行被视为“当前”,“当前”或“有效”。类似的注意事项适用于CustomerAddressHistory
行。
的CustomerAddress.IsActive
BIT(布尔值)列是为了指出一定是否Address
行是由“可用” Customer
行与否; 例如,如果将其设置为“ false”,则将传达一个事实,即客户不再使用该地址,因此不能将其用于新Orders。
注:在另一方面,我也看到了一些系统中,每一个新的时间顺序是effectuated的地址信息必须输入(有时反复),以及地址(ES)用于过去订单从不删除(因此(订单不受地址更改的影响)。
此操作过程肯定会涉及大量的冗余,但是有可能-根据您业务领域的确切信息要求-可能起作用,因此您也可能希望评估其优缺点。
资料检索
表中的行必须包含地址出现的“当前”,“当前”或“有效”版本Address
,但是从(或从)表中选择地址的先前“状态” 很容易,并且可能做一个有趣的练习来增强您的SQL编码技能。AddressHistory
CustomerAddressHistory
对于您在注释中提到的情况之一,如果要从中检索单个Address
行的“倒数第二个版本” AddressHistory
,则必须考虑与当前特定值匹配的MAX(AddressHistory.AuditedDateTime)
和。AddressHistory.AddressId
Address.AddressId
在这方面(至少在构建关系数据库时),首先定义相应的概念模式(基于适用的业务规则),然后声明其后续的逻辑 DDL布置是非常方便的。一旦获得了这些基本元素的稳定和可靠的版本(当然,它们会随着时间的推移而发展),就可以分析和确定最佳的操作方式(通过INSERT,UPDATE,DELETE和SELECT操作或它们的组合)了。关于数据。
最终用户的看法,观点和应用程序帮助
显然,在外部抽象级别上,(最终用户)将地址信息视为Order的一部分,并且这没有错,但这并不意味着建模者必须设计该信息的重要部分。这样的数据库。在这一点上,如果需要例如打印“完整” 订单(非常可行),则可以在一些JOIN运算符和WHERE子句的帮助下按需“复制”该订单(考虑有效期)等)固定在将来的视图中,以将相关结果集发送到相关的应用程序,从而可以根据需要增强其格式。
当然,当执行订单时,应用程序也将非常有帮助;例如,桌面/移动应用程序窗口或网页可以:
- 仅显示地址(ES)的是所涉及的客户已经确立为“可用”(通过
CustomerAddress.IsActive
);
- 名单在一起的所有地址的客户已经为计费服务使能(通
CustomerAddress.IsBilling
); 和
- 将客户为运输服务定义的所有地址分组(通过);
CustomerAddress.IsShipping
以这种方式促进了GUI上所有涉及的过程(即,计算机化系统的外部抽象级别)。
建议阅读
您要求(在现在删除的注释中)有关声音数据库文献的一些提示;因此,对于理论的材料,我强烈建议你阅读了书面工作EF科德博士,一个图灵奖收件人和,当然还有独家发起的的数据的关系模型(也许现在比以往任何时候都更相关)。这份名单包括他一些很有影响力的文章和论文。
上述清单中未包括的两项重要著作,确切地说是1981年的ACM图灵奖讲座,题为“ 关系数据库:生产力的实用基础”,其书名为《数据库管理的关系模型:第2版》,已出版。在1990年。
在概念设计方面,信息建模的集成定义(IDEF1X)是一项值得强烈推荐的技术,美国国家标准技术研究院(NIST)于1993年12月将其定义为标准。