yem*_*met 2 mysql foreign-key database-design primary-key many-to-many
我有以下三个表:
products:
product_id,
product_name,
...
categories:
category_id,
category_name,
category_parent_id,
category_priority (for sort ordering),
.....
labels:
label_id,
label_name,
.....
Run Code Online (Sandbox Code Playgroud)
这个想法是,产品分配给一个类别将各内进行分组类别的标签,并以这种方式在网站上列出:
---label1---
product_1
product_2
product_3
---label2---
product_4
product_5
---label3---
product_6
product_7
product_8
product_9
etc.
Run Code Online (Sandbox Code Playgroud)
我不知道如何设计一个关联表(或多个表)将所有这些粘合在一起并防止这样的异常:
---label1---
product_1
product_2
---label2---
product_2
product_3
Run Code Online (Sandbox Code Playgroud)
同时,我想允许一种情况,即当没有足够的产品来证明其合理性时,不会为某个类别分配标签。
是否有可能设计一个将它结合在一起的结构,或者我应该“放弃所有希望”并采用这样的方法:
categories:
category_id,
category_name,
category_parent_id,
categor_is_label,
category_priority
products:
product_id,
product_name,
...
Run Code Online (Sandbox Code Playgroud)
加上下面的关联表:
categories_products:
category_id,
product_id,
priority
Run Code Online (Sandbox Code Playgroud)
并处理应用程序中的所有逻辑和异常检查?
我假设用户不能直接访问数据库。
对于那些有兴趣深入讨论手头业务背景的人,您可以访问此聊天室。
注意:此答案提供了一种方法,专门涵盖通过最早的一系列评论和聊天交互(其中大部分可以在此问题修订版中看到)派生的业务规则。尽管如此,在进行了更深入的澄清和审议之后,@yemet表示,由于对不同业务规则的连续识别,业务上下文可能需要某种不同的方法。
您已经确定存在涉及感兴趣的实体类型(一旦实现的表)的三向关联(也称为三元或菱形关系)这一事实表明您正朝着正确的方向前进。
目标应该是分别处理手头的三种不同关系,在全面考虑实施方面之前从逻辑级别分析开始。在这方面,写下一些描述相关业务规则的公式是很有帮助的,例如:
首先,对于以下多对多 (M:N) 关系:
A product is classified by one-to-many categories
A category classifies zero-one-or-many products
这意味着存在我将要调用的关联实体类型product_category
。
其次,对于不同的 M:N 关系:
A category is integrated by zero-one-or-many labels
A label integrates zero-one-or-many categories
表明存在另一种关联实体类型的情况,在这种情况下,我将命名为category_label
。
然后,是时候管理另一个 M:N 关系,这次是在上面讨论的两个关联实体类型之间:
A product_category may receive zero-one-or-many label_assignments
A category_label may take part in zero-one-or-many label_assignments
如前所述,我已经包含了一个我命名的新实体类型,label_assignment
但是,自然地,您可以使用对您的业务领域更有意义的术语来命名它。
我已经假设,根据categories
您的问题中包含的表的结构(特别是列categories.category_parent_id
),存在关于名为 的实体类型的自递归一对多 (1:M) 关系category
。后来你确认了这种情况,所以下面的规则也适用:
A category comprises zero-one-or-many categories
然后我从上面介绍的业务规则公式中导出了一个 IDEF1X 1逻辑模型,如图 1所示:
通过这种安排,您可以解决大部分需求,因为:
因此,我编写了以下 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)
);
Run Code Online (Sandbox Code Playgroud)
特别注意表的两个复合 FOREIGN KEY 定义label_assignment
,因为category_number
属性包含在它们中。
您提出了一项要求,其中规定:
必须将产品分配到类别才能在商店中可见。
因此,您应该保证每次插入product
一行时,您也可以通过关联表中一行的 INSERTion将它与某个行链接起来,category
这里称为product_category
. 这样,两个操作都应该在同一个ACID TRANSACTION 中执行,以便它们作为一个单元要么成功要么失败。
你可能会发现我的回答对你有帮助
还有@Ypercube??回答
1.对信息建模(综合定义IDEF1X)是被确立为一个非常可取的数据建模技术标准通过标准的美国国家技术研究所(NIST)于1993年12月。它坚实基础的(一)理论著作撰写由始发的的关系模型,即EF科德博士; 关于 (b)实体关系视图,由PP Chen 博士开发;以及 (c) 逻辑数据库设计技术,由 Robert G. Brown 创建。值得注意的是,IDEF1X 是通过一阶逻辑形式化的。