dpo*_*tar 16 normalization database-design denormalization many-to-many
我对数据库设计比较陌生,我决定制作自己的假设数据库以进行实践。但是,我无法对其进行建模和规范化,因为我认为存在许多多对多 (M:N) 关系。
该数据库旨在保留有关在塞尔达系列中工作过的各种人物的数据。我想跟踪的控制台(S) ,一个游戏可以玩上,员工是曾在部分游戏的发展,乔布斯的员工有(很多员工在不同的工作职位在多个游戏等)
到目前为止,无论我设计什么,似乎到处都存在感兴趣的实体类型之间的数据冗余和 M:N 关系。不过我觉得数据库设计者一定会经常遇到这样的问题,所以一定要有解决的办法。
注意:我很容易找到填充表格的数据,问题是将它组织到一个包含规范化表格的数据库中。
MDC*_*CCL 18
是的,多对多(简称 M:N)关联或关系的识别是数据库从业者在布置概念模式时非常常见的情况。所述基数比率的关联出现在性质非常不同的业务环境中,并且当通过例如 SQL-DDL 安排在逻辑级别正确表示时,它们不会引入有害的冗余。
这样,数据库建模练习的目标应该是高精度地反映感兴趣的业务上下文的相关特征;因此,如果您正确地识别出有许多 M:N 关联,那么您必须在 (a) 概念模式和 (b) 相应的逻辑级声明中表达它们,无论它们有多少连接 - 或任何必须解决其他类型的基数比率。
您提供了一个充分背景化的问题,并澄清了您正在使用的数据库纯粹是假设性的,这一点很重要,因为我认为像所考虑的那样的“真实世界”业务场景会更广泛因此,将意味着更复杂的信息需求。
我决定 (1) 对您提供的业务规则进行一些修改和扩展,以便 (2) 生成更具描述性的概念模式——尽管仍然是假设性的——。以下是我整理的一些公式:
1 Party是在法律上下文中使用的一个术语,用于指代组成单个实体的个人或一组个人,因此该名称适合代表人员和组织。
IDEF1X图
随后,我创建了图 1 中所示的 IDEF1X 2图表(确保单击链接以更高的分辨率查看它),将上面显示的业务规则(以及其他一些看起来相关的规则)整合到单个图形设备中:
2 对于信息建模集成定义(IDEF1X)是被确立为一个非常可取的数据建模技术标准是由美国在1993年12月美国国家标准与技术研究院(NIST)。它基于 (a) 关系模型的唯一创始人,即 EF Codd 博士撰写的早期理论材料;关于 (b) 数据的实体关系视图,由PP Chen 博士开发;以及 (c) 逻辑数据库设计技术,由 Robert G. Brown 创建。
如您所见,我仅通过相应的关联实体类型描述了三个 M:N 关联,即:
在其他方面,有两个不同的超类型-子类型结构,其中:
Person和Organization是Party 的互斥实体子类型,它们的实体超类型
Product是System和Game的超类型,它们又是互斥的子类型
如果您不熟悉超类型-子类型关联,您可能会找到帮助,例如,我对以下问题的回答:
随后,我们必须确保在逻辑层面上:
所以我根据之前显示的 IDEF1X 图声明了以下 DDL 安排:
CREATE TABLE PartyType ( -- Stands for an independent entity type.
PartyTypeCode CHAR(1) NOT NULL, -- To retain 'P' or 'O'.
Name CHAR(30) NOT NULL, -- To keep 'Person' or 'Organization'.
--
CONSTRAINT PartyType_PK PRIMARY KEY (PartyTypeCode)
);
CREATE TABLE Party ( -- Represents an entity supertype.
PartyId INT NOT NULL,
PartyTypeCode CHAR(1) NOT NULL, -- To hold the value that indicates the type of the row denoting the complementary subtype occurrence: either 'P' for 'Person' or 'O' for 'Organization'.
CreatedDateTime TIMESTAMP NOT NULL,
--
CONSTRAINT Party_PK PRIMARY KEY (PartyId),
CONSTRAINT PartyToPartyType_FK FOREIGN KEY (PartyTypeCode)
REFERENCES PartyType (PartyTypeCode)
);
CREATE TABLE Person ( -- Denotes an entity subtype.
PersonId INT NOT NULL, -- To be constrained as (a) the PRIMARY KEY and (b) a FOREIGN KEY.
FirstName CHAR(30) NOT NULL,
LastName CHAR(30) NOT NULL,
GenderCode CHAR(3) NOT NULL,
BirthDate DATE NOT NULL,
--
CONSTRAINT Person_PK PRIMARY KEY (PersonId),
CONSTRAINT Person_AK UNIQUE (FirstName, LastName, GenderCode, BirthDate), -- Composite ALTERNATE KEY.
CONSTRAINT PersonToParty_FK FOREIGN KEY (PersonId)
REFERENCES Party (PartyId)
);
CREATE TABLE Organization ( -- Stands for an entity subtype.
OrganizationId INT NOT NULL, -- To be constrained as (a) the PRIMARY KEY and (b) a FOREIGN KEY.
Name CHAR(30) NOT NULL,
FoundingDate DATE NOT NULL,
--
CONSTRAINT Organization_PK PRIMARY KEY (OrganizationId),
CONSTRAINT Organization_AK UNIQUE (Name), -- Single-column ALTERNATE KEY.
CONSTRAINT OrganizationToParty_FK FOREIGN KEY (OrganizationId)
REFERENCES Party (PartyId)
);
CREATE TABLE ProductType ( -- Represents an independent entity type.
ProductTypeCode CHAR(1) NOT NULL, -- To enclose the values 'S' and 'G' in the corresponding rows.
Name CHAR(30) NOT NULL, -- To comprise the values 'System' and 'Person' in the respective rows.
--
CONSTRAINT ProductType_PK PRIMARY KEY (ProductTypeCode)
);
CREATE TABLE Product ( -- Denotes an entity supertype.
OrganizationId INT NOT NULL,
ProductNumber INT NOT NULL,
ProductTypeCode CHAR(1) NOT NULL, -- To keep the value that indicates the type of the row denoting the complementary subtype occurrence: either 'S' for 'System' or 'G' for 'Game'.
CreatedDateTime DATETIME NOT NULL,
--
CONSTRAINT Product_PK PRIMARY KEY (OrganizationId, ProductNumber), -- Composite PRIMARY KEY.
CONSTRAINT ProductToOrganization_FK FOREIGN KEY (OrganizationId)
REFERENCES Organization (OrganizationId),
CONSTRAINT ProductToProductType_FK FOREIGN KEY (ProductTypeCode)
REFERENCES ProductType (ProductTypeCode)
);
CREATE TABLE SystemType ( -- Stands for an independent entity type.
SystemTypeCode CHAR(1) NOT NULL,
Name CHAR(30) NOT NULL,
--
CONSTRAINT SystemType_PK PRIMARY KEY (SystemTypeCode)
);
CREATE TABLE MySystem ( -- Represents a dependent entity type.
OrganizationId INT NOT NULL, -- To be constrained as (a) the PRIMARY KEY and (b) a FOREIGN KEY.
SystemNumber INT NOT NULL,
SystemTypeCode CHAR(1) NOT NULL,
ParticularColumn CHAR(30) NOT NULL,
--
CONSTRAINT System_PK PRIMARY KEY (OrganizationId, SystemNumber),
CONSTRAINT SystemToProduct_FK FOREIGN KEY (OrganizationId, SystemNumber)
REFERENCES Product (OrganizationId, ProductNumber),
CONSTRAINT SystemToSystemType_FK FOREIGN KEY (SystemTypeCode)
REFERENCES SystemType (SystemTypeCode)
);
CREATE TABLE Game ( -- Denotes an entity subtype.
OrganizationId INT NOT NULL, -- To be constrained as (a) the PRIMARY KEY and (b) a FOREIGN KEY.
GameNumber INT NOT NULL,
SpecificColumn CHAR(30) NOT NULL,
--
CONSTRAINT Game_PK PRIMARY KEY (OrganizationId, GameNumber),
CONSTRAINT GameToProduct_FK FOREIGN KEY (OrganizationId, GameNumber)
REFERENCES Product (OrganizationId, ProductNumber)
);
CREATE TABLE Genre ( -- Stands for an independent entity type.
GenreNumber INT NOT NULL,
Name CHAR(30) NOT NULL,
Description CHAR(90) NOT NULL,
--
CONSTRAINT Genre_PK PRIMARY KEY (GenreNumber),
CONSTRAINT Genre_AK1 UNIQUE (Name),
CONSTRAINT Genre_AK2 UNIQUE (Description)
);
CREATE TABLE SystemGame ( -- Represents an associative entity type or M:N association.
SystemOrganizationId INT NOT NULL,
SystemNumber INT NOT NULL,
GameOrganizationId INT NOT NULL,
GameNumber INT NOT NULL,
CreatedDateTime DATETIME NOT NULL,
--
CONSTRAINT SystemGame_PK PRIMARY KEY (SystemOrganizationId, SystemNumber, GameOrganizationId, GameNumber), -- Composite PRIMARY KEY.
CONSTRAINT SystemGameToSystem_FK FOREIGN KEY (SystemOrganizationId, SystemNumber) -- Multi-column FOREIGN KEY.
REFERENCES MySystem (OrganizationId, SystemNumber),
CONSTRAINT SystemGameToGame_FK FOREIGN KEY (SystemOrganizationId, GameNumber) -- Multi-column FOREIGN KEY.
REFERENCES Game (OrganizationId, GameNumber)
);
CREATE TABLE GameGenre ( -- Denotes an associative entity type or M:N association.
GameOrganizationId INT NOT NULL,
GameNumber INT NOT NULL,
GenreNumber INT NOT NULL,
CreatedDateTime DATETIME NOT NULL,
--
CONSTRAINT GameGenre_PK PRIMARY KEY (GameOrganizationId, GameNumber, GenreNumber), -- Composite PRIMARY KEY.
CONSTRAINT GameGenreToGame_FK FOREIGN KEY (GameOrganizationId, GameNumber)
REFERENCES Game (OrganizationId, GameNumber), -- Multi-column FOREIGN KEY.
CONSTRAINT GameGenreToGenre_FK FOREIGN KEY (GenreNumber)
REFERENCES Genre (GenreNumber)
);
CREATE TABLE Job ( -- Stands for an associative entity type or M:N association.
OrganizationId INT NOT NULL,
ProductNumber INT NOT NULL,
JobNumber INT NOT NULL,
Title CHAR(30) NOT NULL,
CreatedDateTime DATETIME NOT NULL,
--
CONSTRAINT Job_PK PRIMARY KEY (OrganizationId, ProductNumber, JobNumber), -- Composite PRIMARY KEY.
CONSTRAINT Job_AK UNIQUE (Title), -- Single-column ALTERNATE KEY.
CONSTRAINT JobToProduct_FK FOREIGN KEY (OrganizationId, ProductNumber) -- Multi-column FOREIGN KEY.
REFERENCES Product (OrganizationId, ProductNumber)
);
CREATE TABLE Collaborator ( -- Represents an associative entity type or M:N association.
CollaboratorId INT NOT NULL,
OrganizationId INT NOT NULL,
ProductNumber INT NOT NULL,
JobNumber INT NOT NULL,
AssignedDateTime DATETIME NOT NULL,
--
CONSTRAINT Collaborator_PK PRIMARY KEY (CollaboratorId, OrganizationId, ProductNumber, JobNumber), -- Composite PRIMARY KEY.
CONSTRAINT CollaboratorToPerson_FK FOREIGN KEY (CollaboratorId)
REFERENCES Person (PersonId),
CONSTRAINT CollaboratorToJob_FK FOREIGN KEY (OrganizationId, ProductNumber, JobNumber) -- Multi-column FOREIGN KEY.
REFERENCES Job (OrganizationId, ProductNumber, JobNumber)
);
Run Code Online (Sandbox Code Playgroud)
需要强调的是,在多个表中存在复合PRIMARY KEY 约束的声明,它们代表概念实体类型之间发生的连接层次结构,当例如表达 SELECT 时,这种安排对于数据检索非常有益包含 JOIN 子句以获取派生表的操作。
是的,(i)每个 M:N 关联和(ii)每个关联实体类型都由(iii)逻辑 DDL 结构中的相应表表示,因此要特别注意 PRIMARY 和 FOREIGN KEY 约束(以及我留下的注释)代表这些概念元素的表格,因为它们有助于确保相关行之间的连接满足适用的基数比。
EF Codd 博士从关系范式的起源开始就引入了复合键的使用,正如他在 1970 年题为“大型共享数据库的关系模型”(准确地说,还介绍了处理概念性 M:N 关联的最优雅方法)。
我放置了 一个 db<>fiddle和一个 SQL Fiddle,它们都在 Microsoft SQL Server 2014 上运行,以便可以“实际”测试结构。
归一化是一个逻辑级别的过程,它基本上意味着:
通过第一范式消除非原子列,以便使用数据子语言(例如 SQL)更容易处理数据操作和压缩。
借助连续的范式摆脱特定表的列之间的不良依赖关系,以避免更新异常。
自然,人们必须考虑所讨论的表和列所承载的含义。
我喜欢将规范化视为一种建立在科学基础上的测试,设计师一旦描绘出一个稳定的逻辑级别安排,就可以将其应用于相关元素,以确定其项目是否符合每个规范形式。然后,如果需要,设计者会采取适当的纠正措施。
冗余
在关系模型中,虽然列中包含的值的重复不仅是可以接受的而且是预期的,但禁止重复的行。就此而言,据我所知,在之前公开的逻辑布局中包含的所有表中都防止了重复行和其他类型的有害冗余,也许您想澄清您在这方面的担忧。
无论如何,您当然可以 (a) 通过范式对您自己的所述结构进行评估,以定义它是否满足要求,以及 (b) 在必要时对其进行修改。
您通过评论提出了另一个重要方面(发布在现已删除的答案中):
每次我尝试建造一座桥梁时,这座桥梁中的元素也有一个多对多的关系,我的印象是不允许或至少不鼓励。
这种情况似乎表明您关注的问题之一与概念三元关联有关。基本上,这种关联发生在存在 (1) 涉及 (2) 两个其他关系的关系时,换句话说,“关系之间的关系”——也是一种典型情况,因为关系本身就是一个实体——。
这些安排如果管理得当,也不会带来有害的冗余。而且,是的,如果在某个用例中,您确定此类关系出现在“现实世界”实体类型之间,则您必须 (i) 建模并 (ii) 在逻辑级别准确地声明它们。
归档时间: |
|
查看次数: |
4905 次 |
最近记录: |