标签:mysql database-design primary-key many-to-many foreign-key
我有以下三个表:
products:
product_id,
product_name,
...
categories:
category_id,
category_name,
category_parent_id,
category_priority (for sort ordering),
.....
labels:
label_id,
label_name,
.....
我们的想法是,分配给某个类别的产品将按标签分组到每个类别中,并以这种方式在网站上列出:
---label1---
product_1
product_2
product_3
---label2---
product_4
product_5
---label3---
product_6
product_7
product_8
product_9
etc.
我无法弄清楚如何设计一个将所有这些粘合在一起的关联表(或表),以防止这样的异常:
---label1---
product_1
product_2
---label2---
product_2
product_3
与此同时,我想允许一种情况,即当没有足够的产品证明它时,没有标签分配给某个类别.
问题
是否有可能设计一种能够将它结合在一起的结构,或者我是否应该“放弃所有的希望”,并采取类似的方式:
categories:
category_id,
category_name,
category_parent_id,
categor_is_label,
category_priority
products:
product_id,
product_name,
...
加上下面的关联表:
categories_products:
category_id,
product_id,
priority
并处理所有逻辑并检查应用程序中的异常情况?
我假设用户不能直接访问数据库.
评论和聊天互动
对于那些对手头业务背景深入讨论感兴趣的人,可以访问this chat room.
解决方法:
注意:此答案提供了一种方法,专门涵盖通过最早的评论和聊天交互系列得出的业务规则(其中大多数可以在this question revision中看到).尽管如此,在进一步深入clarifications and deliberations之后,@yemet表明由于不断识别不同的业务规则,业务环境可能需要一种稍微不同的方法.
您已经确定存在涉及感兴趣的实体类型(一旦实施的表格)的三向关联(也称为三元关系或菱形关系)这一事实表明您正朝着正确的方向前进.
商业规则
目标应该是在完全考虑实施方面之前,分别处理手头的三个不同关系,从逻辑层面分析开始.在这方面,写下描述相关业务规则的一些表述是非常有帮助的,例如:
首先,对于以下多对多(M:N)关系:
>产品按一对多类别分类
>类别对零一个或多个产品进行分类
这意味着存在一个我将称之为product_category的关联实体类型.
其次,对于明显的M:N关系:
>通过零一个或多个标签集成类别
>标签集成了零一个或多个类别
表明存在另一个关联实体类型的情况,在这种情况下,我将命名为category_label.
然后,是时候管理另一个M:N关系,这次是在上面讨论的两个关联实体类型之间:
> product_category可能会收到零一个或多个label_assignments
> category_label可以参与零一个或多个label_assignments
如上所述,我已经包含了一个新的实体类型,我将其命名为label_assignment,但当然,您可以使用对您的业务领域更有意义的术语来命名它.
我假设,基于您的问题中包含的类别表的结构(特别是列categories.category_parent_id),有一个关于称为类别的实体类型的自递归一对多(1:M)关系.之后,您确认了这种情况,因此以下规则也适用:
>类别包括零个或多个类别
逻辑模型
然后,我从上面提到的业务规则公式派生了一个IDEF1X1逻辑模型,如Figure 1所示:
通过这种安排,您可以解决您的大部分需求,因为:
>每个产品在收到标签分配之前必须首先与某个类别相关.
>如果标签之前未连接到某个类别,则无法将其分配给特定产品.
>产品可以与某个类别相关,而不必涉及与标签的关系.
说明性DDL结构
因此,我编写了以下DDL结构(在SQL Fiddle测试):
-- You should determine which are the most fitting
-- data types and sizes for all your table columns
-- depending on your business context characteristics.
-- As one would expect, you are free to make use of
-- your preferred (or required) naming conventions.
CREATE TABLE product
(
product_id INT NOT NULL,
product_code CHAR(30) NOT NULL,
name CHAR(30) NOT NULL,
description CHAR(90) NOT NULL,
created_datetime DATETIME NOT NULL,
CONSTRAINT PK_product PRIMARY KEY (product_id),
CONSTRAINT AK_product_code UNIQUE (product_code), -- (Possible?) ALTERNATE KEY.
CONSTRAINT AK_product_name UNIQUE (name), -- ALTERNATE KEY.
CONSTRAINT AK_product_description UNIQUE (description) -- ALTERNATE KEY.
);
CREATE TABLE category
(
category_number INT NOT NULL,
parent_category_number INT NULL, -- Set up as ‘NULLable’, in order to focus on the main aspects of the approach exposed.
name CHAR(30) NOT NULL,
description CHAR(90) NOT NULL,
created_datetime DATETIME NOT NULL,
CONSTRAINT PK_category PRIMARY KEY (category_number),
CONSTRAINT AK_category_name UNIQUE (name), -- ALTERNATE KEY.
CONSTRAINT AK_category_description UNIQUE (description), -- ALTERNATE KEY.
CONSTRAINT FK_FROM_category_TO_parent_category FOREIGN KEY (parent_category_number)
REFERENCES category (category_number)
);
CREATE TABLE label
(
label_number INT NOT NULL,
name CHAR(30) NOT NULL,
description CHAR(90) NOT NULL,
created_datetime DATETIME NOT NULL,
CONSTRAINT PK_label PRIMARY KEY (label_number),
CONSTRAINT AK_label_name UNIQUE (name), -- ALTERNATE KEY.
CONSTRAINT AK_label_description UNIQUE (description) -- ALTERNATE KEY.
);
CREATE TABLE product_category -- Associative table.
(
product_id INT NOT NULL,
category_number INT NOT NULL,
classified_datetime DATETIME NOT NULL,
CONSTRAINT PK_product_category PRIMARY KEY (product_id, category_number),
CONSTRAINT FK_FROM_product_category_TO_product FOREIGN KEY (product_id)
REFERENCES product (product_id),
CONSTRAINT FK_FROM_product_category_TO_category FOREIGN KEY (category_number)
REFERENCES category (category_number)
);
CREATE TABLE category_label -- Associative table.
(
category_number INT NOT NULL,
label_number INT NOT NULL,
integrated_datetime DATETIME NOT NULL,
CONSTRAINT PK_category_label PRIMARY KEY (category_number, label_number),
CONSTRAINT FK_FROM_category_label_TO_category FOREIGN KEY (category_number)
REFERENCES category (category_number),
CONSTRAINT FK_FROM_category_label_TO_label FOREIGN KEY (label_number)
REFERENCES label (label_number)
);
CREATE TABLE label_assignment -- Associative table that ‘concretizes’ a relationship between two distinct relationships.
(
product_id INT NOT NULL,
category_number INT NOT NULL,
label_number INT NOT NULL,
assigned_datetime DATETIME NOT NULL,
CONSTRAINT PK_label_assignment PRIMARY KEY (product_id, category_number, label_number), -- Composite PRIMARY KEY.
CONSTRAINT FK_FROM_label_assignment_TO_product_category FOREIGN KEY (product_id, category_number) -- Composite FOREIGN KEY.
REFERENCES product_category (product_id, category_number),
CONSTRAINT FK_FROM_label_assignment_TO_category_label FOREIGN KEY (category_number, label_number) -- Composite FOREIGN KEY.
REFERENCES category_label (category_number, label_number)
);
请特别注意label_assignment表的两个复合FOREIGN KEY定义,因为category_number属性包含在它们中.
你提出了一项要求,规定:
A product has to be assigned to category in order to be visible in the shop.
因此,您应该保证每次插入产品行时,您也可以通过关联表中名为product_category的行的INSERTion将其与某个类别链接起来.这样,两个操作都应该在同一个ACID TRANSACTION中执行,这样它们就可以作为一个单元成功或失败.
类似的场景
您可能会找到帮助我的回答
> Best data modelling approach to handle redundant foreign keys in relational model,
还有@Ypercubeᵀᴹ的答案
> Many to Many and Weak Entities
尾注
1.信息建模的集成定义(IDEF1X)是一种非常值得推荐的数据建模技术,由美国国家标准与技术研究院(NIST)于1993年12月作为标准建立.它完全基于(a)由Relational Model的发起人撰写的理论着作,即Dr. E. F. Codd; (b)Entity-Relationship view,由Dr. P. P. Chen开发;以及(c)由Robert G. Brown创建的逻辑数据库设计技术.值得注意的是,IDEF1X是通过一阶逻辑形式化的.
标签:mysql,database-design,primary-key,many-to-many,foreign-key 来源: https://codeday.me/bug/20190806/1600590.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。