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

时间:2019-12-01 17:12:50

标签: mysql foreign-keys constraints

我一直在从事有关游戏租赁商店的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);

AND:

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);

AND:

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));

2 个答案:

答案 0 :(得分:0)

外键必须引用父表的PRIMARY KEY或UNIQUE KEY。

外键的所有列必须与其引用的键中的列匹配,并且它们必须是相同的数据类型和相同的顺序。

在您的情况下,您在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表中。

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

答案 1 :(得分:0)

错误消息的原因是,您具有引用另一个表中的列元组的外键约束,在该表中该元组中的列没有(唯一)索引(以相同的顺序)。即约束FK_OPENTRAN_RENTALFK_OPENTRAN_INV

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

因此,列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));