mysql 中的多对多关系必须是两个表连接表中的外键主键?
many to many relationship in mysql have to be the foreign keys the primary keys from both tables connections tables?
假设我有一个订单 table 和商品 table :
CREATE TABLE if not exists ORDERS (
ORDERID INTEGER AUTO_INCREMENT,
ORDERTYPE VARCHAR (20) NOT NULL,
ShippedTime VARCHAR(40),
ORDERDATE DATE,
PRIMARY KEY (ORDERID),
);
CREATE TABLE if not exists ITEM(
ITEMID INTEGER AUTO_INCREMENT,
NAME VARCHAR (20) NOT NULL,
PRICE INTEGER NOT NULL CHECK (PRICE > 0),
PRIMARY KEY (ITEMID)
);
并且两个 table 之间的关系将存在:
CREATE TABLE if not exists EXISTOF (
ORDERID INTEGER NOT NULL,
ITEMID INTEGER NOT NULL,
FOREIGN KEY (ORDERID) REFERENCES ORDERS(ORDERID) ON DELETE CASCADE,
FOREIGN KEY (ITEMID) REFERENCES ITEM(ITEMID) ON DELETE CASCADE,
PRIMARY KEY (ORDERID,ITEMID)
);
解释应该是每个订单有多个商品,每个商品属于多个订单。
如果我这样做,它将不起作用,因为 ID 是主键,我不能为特定订单插入多个项目,而且它不能属于多个订单的项目。
有没有人有任何建议如何做到这一点?
使用外键 item_id 和 order_id 创建中间 table OrderItems。还有其他选择,但这是我发现打破多对多关系的最简单方法!
您的 Existof Table 不够灵活。大多数订单处理系统处理这种情况的方法是在 Existof table 中添加一列,我们可以称之为 Quantity。默认值为1,但也可以输入其他数量。
因此,如果给定的订单想要订购 5 令纸,并且产品中有令纸,则 Existof 中该项目的条目数量将为 5。
这假设所有 5 令都是可互换的,因此由相同的数据描述。如果有些纸令有不同的颜色,那么它们应该是不同的产品。
“……必须……”——不。 FOREIGN KEYs
永远不是“必需的”。
FK 提供三样东西:
- 动态检查是否存在匹配元素。这对于数据的完整性检查很有用,但不是强制性的。
- An
INDEX
使上述检查明显更快。手动指定 INDEX
也一样好。无论如何,PRIMARY KEY
是一个索引。
- “级联删除等”。这是很少有模式使用甚至需要的选项。
table之间有 3 种主要的“关系”:
1:1 -- 但为什么要有两个 table 呢?这些列可以简单地位于单个 table 中。 (也有例外。)
1:many --(这听起来像“一个订单中的许多项目”??)只需在 Items
table 中添加 order_id
即可实现。 (并索引该列。)可选地,它可以是 FK。别人叫tableOrderItems
。它链接到 Products
table.
many:many——这是当你需要一个额外的 table 时(通常)正好有两列,即 ids 到另外两个 tables 中。 (例如,Student vs class)每一列都可以是 FK,但最佳索引是 PRIMARY KEY(a_id, b_id)
和 INDEX(b_id, a_id)
。 FKs 会看到您已经有以 a_id 和 b_id 开头的索引,因此它不会创建额外的索引。没有“唯一的联结 table ID”;它比我在这里建议的 PK 效率低。 (更多讨论:http://mysql.rjweb.org/doc.php/index_cookbook_mysql#many_to_many_mapping_table)
回到您提出的设计。我建议“项目”暗示该产品的产品和数量以及当时收取的价格。因此它需要是 1:many。而那个“产品”就是你所想的。请更改 table 名称以免我混淆。
现在,另一个问题...价格。价格是永远固定的吗?还是今天的订单价格会与昨天的不同?同样,项目和价格与 一个 订单相关联。产品上可能有价格 table,可能是“current_price”,在创建新订单时会用到。
ShippedTime VARCHAR(40)
-- 也许应该是 DATETIME
?
假设我有一个订单 table 和商品 table :
CREATE TABLE if not exists ORDERS (
ORDERID INTEGER AUTO_INCREMENT,
ORDERTYPE VARCHAR (20) NOT NULL,
ShippedTime VARCHAR(40),
ORDERDATE DATE,
PRIMARY KEY (ORDERID),
);
CREATE TABLE if not exists ITEM(
ITEMID INTEGER AUTO_INCREMENT,
NAME VARCHAR (20) NOT NULL,
PRICE INTEGER NOT NULL CHECK (PRICE > 0),
PRIMARY KEY (ITEMID)
);
并且两个 table 之间的关系将存在:
CREATE TABLE if not exists EXISTOF (
ORDERID INTEGER NOT NULL,
ITEMID INTEGER NOT NULL,
FOREIGN KEY (ORDERID) REFERENCES ORDERS(ORDERID) ON DELETE CASCADE,
FOREIGN KEY (ITEMID) REFERENCES ITEM(ITEMID) ON DELETE CASCADE,
PRIMARY KEY (ORDERID,ITEMID)
);
解释应该是每个订单有多个商品,每个商品属于多个订单。 如果我这样做,它将不起作用,因为 ID 是主键,我不能为特定订单插入多个项目,而且它不能属于多个订单的项目。 有没有人有任何建议如何做到这一点?
使用外键 item_id 和 order_id 创建中间 table OrderItems。还有其他选择,但这是我发现打破多对多关系的最简单方法!
您的 Existof Table 不够灵活。大多数订单处理系统处理这种情况的方法是在 Existof table 中添加一列,我们可以称之为 Quantity。默认值为1,但也可以输入其他数量。
因此,如果给定的订单想要订购 5 令纸,并且产品中有令纸,则 Existof 中该项目的条目数量将为 5。
这假设所有 5 令都是可互换的,因此由相同的数据描述。如果有些纸令有不同的颜色,那么它们应该是不同的产品。
“……必须……”——不。 FOREIGN KEYs
永远不是“必需的”。
FK 提供三样东西:
- 动态检查是否存在匹配元素。这对于数据的完整性检查很有用,但不是强制性的。
- An
INDEX
使上述检查明显更快。手动指定INDEX
也一样好。无论如何,PRIMARY KEY
是一个索引。 - “级联删除等”。这是很少有模式使用甚至需要的选项。
table之间有 3 种主要的“关系”:
1:1 -- 但为什么要有两个 table 呢?这些列可以简单地位于单个 table 中。 (也有例外。)
1:many --(这听起来像“一个订单中的许多项目”??)只需在 Items
table 中添加 order_id
即可实现。 (并索引该列。)可选地,它可以是 FK。别人叫tableOrderItems
。它链接到 Products
table.
many:many——这是当你需要一个额外的 table 时(通常)正好有两列,即 ids 到另外两个 tables 中。 (例如,Student vs class)每一列都可以是 FK,但最佳索引是 PRIMARY KEY(a_id, b_id)
和 INDEX(b_id, a_id)
。 FKs 会看到您已经有以 a_id 和 b_id 开头的索引,因此它不会创建额外的索引。没有“唯一的联结 table ID”;它比我在这里建议的 PK 效率低。 (更多讨论:http://mysql.rjweb.org/doc.php/index_cookbook_mysql#many_to_many_mapping_table)
回到您提出的设计。我建议“项目”暗示该产品的产品和数量以及当时收取的价格。因此它需要是 1:many。而那个“产品”就是你所想的。请更改 table 名称以免我混淆。
现在,另一个问题...价格。价格是永远固定的吗?还是今天的订单价格会与昨天的不同?同样,项目和价格与 一个 订单相关联。产品上可能有价格 table,可能是“current_price”,在创建新订单时会用到。
ShippedTime VARCHAR(40)
-- 也许应该是 DATETIME
?