use*_*321 5 database-design table many-to-many
我有一个 SellerProduct 表。表格中的每一行代表卖家提供的产品信息。SellerProduct 表包含以下列:
id (serial, pk)
productName (nvarchar(50))
productDescription (ntext)
productPrice (decimal(10,2))
sellerId (int, fk to Seller table)
Run Code Online (Sandbox Code Playgroud)
不同卖家的产品可能相同,但每个卖家的 productName、productDescription 和 productPrice 可能不同。
例如,考虑产品 TI-89。卖家 A 可能拥有产品的以下信息:
productName = TI-89 Graphing Calc
productDescription = A graphing calculator that...
productPrice 65.12
Run Code Online (Sandbox Code Playgroud)
卖家 B 可能拥有以下产品信息:
productName = Texas Instrument's 89 Calculator
productDescription = Feature graphing capabilities...
productPrice 66.50
Run Code Online (Sandbox Code Playgroud)
管理员用户需要确定不同卖家的产品是相同的。
我需要一种方法来捕获这些信息(即卖家的产品是相同的)。我可以创建另一个名为 SellerProductMapper 的表,如下所示:
sellerProductId1 (int, pk, fk to SellerProdcut table)
sellerProductId2 (int, pk, fk to SellerProdcut table)
Run Code Online (Sandbox Code Playgroud)
这种方法的问题在于它允许对给定行的 SellerProductId1 和 SellerProductId2 来自同一个卖家。这不应该被允许。
如何在强制执行此约束的同时捕获这种多对多关系?
如果我正确理解你的场景描述,你想要管理两个不同的事实,所以你应该有(a)一个表来存储独立于卖家的产品数据和(b)另一个表来保留在产品与其相应卖家之间的每种关系的上下文。
我在图 1所示的逻辑IDEF1X [1]数据模型中描述了这种方法,您可以从 Dropbox 以 PDF 格式下载它。
正如您在引用模型中看到的那样,您可以使用Product
实体类型(或实现级别的表)来存储产品属性的默认(或基本)值。将此实体视为某种目录会很有用。您可以在此处保留不依赖于卖家的产品数据。
我已经将Product
PK表示ProductNumber
为说明性 porposes,但是,可能ProductCode
在您的业务领域中使用某种或其他类似术语可能更合适或更有利。
然后,我在由和组成的ProductSeller
关联实体中设置了一个 PRIMARY KEY (PK) ,而这些属性又分别是对和 的FOREIGN KEY 引用。您可以在此处存储每个特定卖家定义的产品名称、描述和价格。SellerId
ProductNumber
Party.PartyId
Product.ProductNumber
我决定将Party
在情况下,你必须存储在卖家的实体或者一个Organization
或一个Person
。这三个实体包含在一个独特的超类型-子类型关系中,所以这篇文章可能是相关的。
需要注意的是,我将某些属性表示为 ALTERNATE KEYS(AK 加上其拟合编号),因为这意味着,当它们成为表列时,应使用 UNIQUE CONSTRAINT 或 UNIQUE INDEX 设置它们。
与任何关系数据库开发一样,您应该认真考虑使用ACID 事务以保护您的数据完整性和一致性。
如果在您的情况下只能将 anOrganization
变为 a Seller
,那么您可以使用我在图 2中显示的逻辑模型中建议的结构,并且它也可以作为 PDF 从 Dropbox 下载。
在这种模式下,你只需要迁移[2]在OrganizationId
从PKOrganization
到SellerProduct
,然后为它分配一个角色名。[3]一样SellerId
,以使其更有意义或者,也许,离开它,因为OrganizationId
如果你感觉更舒服。之后,您进行迁移Product.ProductNumber
以完成SellerProduct
PK的组合。
在讨论了两个建议结构中最相关的部分之后,我认为在执行数据输入时处理应该发生的过程是合适的。在这方面——借助与您的数据库通信的应用程序——您的适当授权用户可以:
Product
表中已包含的行进行比较。Product
具有默认值或基本值的新行,以及(1.2)ProductSeller
表中的新行,包括适合SellerId
(从Party.PartyId
或 中提取Organization.OrganizationId
)和ProductNumber
刚刚创建的以及包含该卖家特别描述的产品数据的其余列值。ProductSeller
表中插入一个新行,包括相应的SellerId
和ProductNumber
(取自Product.ProductNumber
) 值以及包含卖家手头指定的产品信息的补充列值。因此,如上所述,ProductSeller.ProductNumber
和ProductSeller.SellerId
对涵盖以下规范非常有用:
管理员用户需要确定不同卖家的产品是相同的。
由于ProductNumber
从多ProductSeller
行引用给定值将帮助您的数据库用户识别和检索由不同卖家提供的产品,他们将通过其独特的SellerId
价值来识别,当然,指向一个精确的Party.PartyId
(或Organization.OrganizationId
)。
由于假设产品数据会随着时间的推移而发生修改似乎是合理的(而且,这些修改可能在大多数情况下都与产品价格有关),因此我认为有必要包含一种机制来跟踪这些变化。这对于我并入计价实体类型的原因ProductHistory
和ProductSellerHistory
在上面给出的逻辑模型。
在这方面,您可能会找到有关时间数据库的这篇文章和有关相关数据版本控制的这篇文章。
当涉及价格时,您可能需要专门跟踪与时间相关的产品修改,因此您也可以使用图 3中描述的模型,您也可以从 Dropbox 以 PDF 格式下载该模型。
这样,让我们将Product
和ProductPrice
实体类型作为引用。正如在这个替代模型中所展示的,我已经将DefaultPrice
属性移到了一个新实体,这个新实体的 PK 由ProductNumber
(也扮演 FK 的角色,引用Product
)和CreatedDateTime
(这将标记 中的确切点插入确定的默认价格的时间)。
因此,每次需要更新默认价格值时,您的数据库用户只需插入一个新ProductPrice
行,其中包含合适的ProductNumber
取自Product
和新价格值。您可以使用服务器功能,以便您可以CreatedDateTime
以可靠的方式检索和存储准确的插入时刻。
产品默认或基本价格出现的当前或有效版本将是包含for a 确定的行,并且所有其他匹配相同的行(如果存在)将是以前的版本。MAX(ProductPrice.CreatedDateTime)
ProductNumber
ProductNumber
DefaultPrice
然后,您可以采用类似的方法来处理与ProductSeller
价格数据相关的变化。
1. 信息建模的集成定义 ( IDEF1X ) 是一种非常值得推荐的数据建模技术,于1993 年 12 月被美国国家标准与技术研究院 ( NIST )定义为标准。它坚实基础的(一)一些理论文章的撰写由始发的的关系模型,即EF科德博士; 关于 (b)实体关系理论,由PP Chen 博士开发;以及 (c)逻辑数据库设计技术,由Robert G. Brown创建。值得注意的是,这项技术是通过一阶逻辑形式化。
2. IDEF1X 将键迁移定义为“将父实体或通用实体的主键作为外键放置在其子实体或类别实体中的建模过程”。
3.自 1970 年以来,Codd 博士在题为“大型共享数据库的数据关系模型”的开创性论文中建议使用角色名称。就其本身而言,IDEF1X——在关系实践方面保持保真——也提倡角色命名。