ERROR 1822(HY000):无法添加外键约束。缺少约束的索引

问题描述 投票:0回答:2

我一直在从事有关游戏租赁商店的sql项目。

我已经创建了下表

CREATE TABLE CUSTOMER(
MEMBERSHIP_ID NUMERIC(10) PRIMARY KEY,
FNAME VARCHAR(10) NOT NULL,
LNAME VARCHAR(10) NOT NULL,
ADDRESS VARCHAR(100) NOT NULL,
TELEFONE NUMERIC(10) NOT NULL,
EMAIL VARCHAR(50) NOT NULL,
BIRTHDAY DATE);

和:

CREATE TABLE INVENTORY(
-> GAME_ID VARCHAR(10) PRIMARY KEY,
-> TITLE VARCHAR(20) NOT NULL,
-> PLATAFORM VARCHAR(10) NOT NULL,
-> EDITION YEAR,
-> GENRE VARCHAR(10) NOT NULL,
-> PUBLISHER VARCHAR(10) NOT NULL,
-> PRICE NUMERIC(4,2) DEFAULT 00.00 NOT NULL);

和:

CREATE TABLE RENTAL (
-> RENTAL_NO VARCHAR(10) PRIMARY KEY,
-> DATE_OUT DATE NOT NULL,
-> DATE_OF_RETURN DATE NOT NULL,
-> MEMBERSHIP_ID NUMERIC(10),
-> GAME_ID VARCHAR(10),
-> INDEX (MEMBERSHIP_ID),
-> CONSTRAINT FK_RENTAL_CUST FOREIGN KEY(MEMBERSHIP_ID) REFERENCES
-> CUSTOMER (MEMBERSHIP_ID),
-> INDEX (GAME_ID),
-> CONSTRAINT FK_RENTAL_INV FOREIGN KEY(GAME_ID) REFERENCES
-> INVENTORY (GAME_ID));

现在我需要一个交易表来连接价格,并且我一直在收到提到的错误:

CREATE TABLE OPEN_TRANSACTION (
RENTAL_NO VARCHAR (10),
MEMBERSHIP_ID NUMERIC (10),
DATE_OUT DATE NOT NULL,
DATE_OF_RETURN DATE NOT NULL,
GAME_ID VARCHAR (10),
ITEM_PRICE NUMERIC(4,2) DEFAULT 00.00 NOT NULL,
INDEX (RENTAL_NO),
INDEX (MEMBERSHIP_ID),
INDEX (GAME_ID),
INDEX (ITEM_PRICE),
INDEX (DATE_OUT),
INDEX (DATE_OF_RETURN),
CONSTRAINT PK_OPEN_TRANSACTION PRIMARY KEY (RENTAL_NO, GAME_ID, DATE_OUT),
CONSTRAINT FK_OPENTRAN_RENTAL FOREIGN KEY (RENTAL_NO, DATE_OUT, DATE_OF_RETURN) REFERENCES
RENTAL (RENTAL_NO, DATE_OUT, DATE_OF_RETURN),
CONSTRAINT FK_OPENTRAN_CUST FOREIGN KEY (MEMBERSHIP_ID) REFERENCES
CUSTOMER (MEMBERSHIP_ID),
CONSTRAINT FK_OPENTRAN_INV FOREIGN KEY (GAME_ID) REFERENCES
INVENTORY (GAME_ID),
CONSTRAINT FK_OPENTRAN_INV FOREIGN KEY (ITEM_PRICE) REFERENCES
INVENTORY (PRICE));
mysql foreign-keys constraints
2个回答
0
投票
外键的所有列必须与它引用的键中的列匹配,并且它们必须是相同的数据类型和相同的顺序。

在您的情况下,您在OPEN_TRANSACTION中具有以下列:RENTAL_NO,DATE_OUT,DATE_OF_RETURN,并且您尝试引用RENTAL表中三个具有相同名称的列,但是RENTAL表的主键只是RENTAL_NO单列。

在我看来,OPEN_TRANSACTION具有单列外键:RENTAL_NO,引用RENTAL(RENTAL_NO)会很好。那将是合法的外键。它不能是模棱两可的,因为RENTAL_NO已经是RENTAL表的主键,因此对于给定的RENTAL_NO值,该表中只有一条记录。

一种替代方法是在RENTAL表中为三列的集合创建一个冗余的UNIQUE KEY。这将允许OPEN_TRANSACTION的三列组成一个外键,但它似乎并不是良好的关系数据库设计。

为什么您在OPEN_TRANSACTIONS表中有DATE_OUT和DATE_OF_RETURN列?如果这些列必须始终具有与RENTAL表中相同的值,则将多余地存储它们。如果这些列可以更改OPEN_TRANSACTIONS表中的值,则不应将它们用作外键。

除了该外键,您还有另一个问题:

ITEM_PRICE上OPEN_TRANSACTIONS中的外键引用INVENTORY.PRICE列,该列不是PRIMARY KEY或UNIQUE KEY。目前尚不清楚为什么要在此列上放置外键,或者为什么要在OPEN_TRANSACTIONS表中存储价格,因为它已经在INVENTORY表中。

我想出的最好的理由是,您想记录购买时的价格,因此您要记录所支付的价格。价格会涨跌,要生成分类账,您需要保存每次购买之日的价格。但是,您将不会在该价格上使用外键来引用库存中的价格,因为将价格复制到另一张表中的整个目的是应该允许值不同。


0
投票
但是您似乎还是误解了外键到底是什么。外键引用其他表中的行,并且不检查两个表中是否有任何奇数列值相同。实际上,您应该将值保留在原始表中,您可以使用外键在另一个表中标识右行并从那里读取信息,从而从另一个表中检索它们。将同一条信息存储在多个位置甚至很危险,因为不同位置的值可能会有所不同,并且您不再知道哪一个是正确的。

因此DATE_OUTDATE_OF_RETURN列不属于OPEN_TRANSACTION。只需在RENTAL_NO中设置OPEN_TRANSACTION。有了它,您可以在RENTAL中找到右行并从中获取值。 ITEM_PRICE中的OPEN_TRANSACTION也一样。您具有GAME_ID外键,可以在INVENTORY中找到合适的游戏,因此也可以找到合适的价格。

相应地更改CREATE语句。删除多余的列也将删除或更改外键约束,从而不再存在错误。

CREATE TABLE OPEN_TRANSACTION ( RENTAL_NO VARCHAR (10), MEMBERSHIP_ID NUMERIC (10), GAME_ID VARCHAR (10), INDEX (RENTAL_NO), INDEX (MEMBERSHIP_ID), INDEX (GAME_ID), CONSTRAINT PK_OPEN_TRANSACTION PRIMARY KEY (RENTAL_NO, MEMBERSHIP_ID, GAME_ID), CONSTRAINT FK_OPENTRAN_RENTAL FOREIGN KEY (RENTAL_NO) REFERENCES RENTAL (RENTAL_NO), CONSTRAINT FK_OPENTRAN_CUST FOREIGN KEY (MEMBERSHIP_ID) REFERENCES CUSTOMER (MEMBERSHIP_ID), CONSTRAINT FK_OPENTRAN_INV FOREIGN KEY (GAME_ID) REFERENCES INVENTORY (GAME_ID));

© www.soinside.com 2019 - 2024. All rights reserved.