我正在研究O'Reilly出版的“学习MySQL”一书,我试图找到该书网站上发布的以下SQL代码:
DROP DATABASE IF EXISTS music;
CREATE DATABASE music;
USE music;
CREATE TABLE artist (
artist_id SMALLINT(5) NOT NULL DEFAULT 0,
artist_name CHAR(128) DEFAULT NULL,
PRIMARY KEY (artist_id)
);
CREATE TABLE album (
artist_id SMALLINT(5) NOT NULL DEFAULT 0,
album_id SMALLINT(4) NOT NULL DEFAULT 0,
album_name CHAR(128) DEFAULT NULL,
PRIMARY KEY (artist_id,album_id),
FOREIGN KEY (artist_id) REFERENCES artist(artist_id)
);
CREATE TABLE track (
track_id SMALLINT(3) NOT NULL DEFAULT 0,
track_name CHAR(128) DEFAULT NULL,
artist_id SMALLINT(5) NOT NULL DEFAULT 0,
album_id SMALLINT(4) NOT NULL DEFAULT 0,
time DECIMAL(5,2) DEFAULT NULL,
PRIMARY KEY (artist_id,album_id,track_id),
FOREIGN KEY (artist_id) REFERENCES artist(artist_id),
FOREIGN KEY (album_id) REFERENCES album(album_id)
);
CREATE TABLE played (
artist_id SMALLINT(5) NOT NULL DEFAULT 0,
album_id SMALLINT(4) NOT NULL DEFAULT 0,
track_id SMALLINT(3) NOT NULL DEFAULT 0,
played TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP,
PRIMARY KEY (artist_id,album_id,track_id,played),
FOREIGN KEY (artist_id) REFERENCES artist(artist_id),
FOREIGN KEY (album_id) REFERENCES album(album_id),
FOREIGN KEY (track_id) REFERENCES track(track_id)
);
-- And the whole bunch of data input into those tables.
INSERT INTO played VALUES (1, 3, 0, "20060814102103");
INSERT INTO artist VALUES (1, "New Order");
INSERT INTO album VALUES (2, 1, "Let Love In");
INSERT INTO track VALUES (0,'Do You Love Me?',2,1,'5.95');
然而,当我尝试SOURCE
MySQL给我ERROR 1215 (HY000): Cannot add foreign key constraint
时
和ERROR 1146 (42s02): Table 'music.track' doesn't exist
。我一直在考虑这个问题。什么似乎是错的?
答案 0 :(得分:1)
您的代码失败的原因是因为您在album
和track
表上有一个复合主键。
为了允许成功创建外键,必须为复合键的每一列的每个表添加另一个索引。
尝试修改每个表的代码以添加索引,如下所示。
在album
表:
INDEX (album_id),
在track
表格上:
INDEX (track_id),
因此,您的完整代码如下所示(不包括数据库创建和插入):
CREATE TABLE artist (
artist_id SMALLINT(5) NOT NULL DEFAULT 0,
artist_name CHAR(128) DEFAULT NULL,
PRIMARY KEY (artist_id)
);
CREATE TABLE album (
artist_id SMALLINT(5) NOT NULL DEFAULT 0,
album_id SMALLINT(4) NOT NULL DEFAULT 0,
album_name CHAR(128) DEFAULT NULL,
PRIMARY KEY (artist_id,album_id),
INDEX (album_id),
FOREIGN KEY (artist_id) REFERENCES artist(artist_id)
);
CREATE TABLE track (
track_id SMALLINT(3) NOT NULL DEFAULT 0,
track_name CHAR(128) DEFAULT NULL,
artist_id SMALLINT(5) NOT NULL DEFAULT 0,
album_id SMALLINT(4) NOT NULL DEFAULT 0,
time DECIMAL(5,2) DEFAULT NULL,
PRIMARY KEY (artist_id,album_id,track_id),
INDEX (track_id),
FOREIGN KEY (artist_id) REFERENCES artist(artist_id),
FOREIGN KEY (album_id) REFERENCES album(album_id)
);
CREATE TABLE played (
artist_id SMALLINT(5) NOT NULL DEFAULT 0,
album_id SMALLINT(4) NOT NULL DEFAULT 0,
track_id SMALLINT(3) NOT NULL DEFAULT 0,
played TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP,
PRIMARY KEY (artist_id,album_id,track_id,played),
FOREIGN KEY (artist_id) REFERENCES artist(artist_id),
FOREIGN KEY (album_id) REFERENCES album(album_id),
FOREIGN KEY (track_id) REFERENCES track(track_id)
);
答案 1 :(得分:1)
您的外键必须引用整个候选键。
CREATE TABLE track (
track_id SMALLINT(3) NOT NULL DEFAULT 0,
track_name CHAR(128) DEFAULT NULL,
artist_id SMALLINT(5) NOT NULL DEFAULT 0,
album_id SMALLINT(4) NOT NULL DEFAULT 0,
time DECIMAL(5,2) DEFAULT NULL,
PRIMARY KEY (artist_id,album_id,track_id),
FOREIGN KEY (artist_id) REFERENCES artist(artist_id),
/* This won't work, not referencing an entire key: */
/*FOREIGN KEY (album_id) REFERENCES album(album_id)*/
/* This should work: */
FOREIGN KEY (artist_id,album_id) REFERENCES album(artist_id,album_id)
);
您必须在播放的表格中进行类似的更改。
Here is a SqlFiddle这些更改,包括以正确的顺序插入数据,以及现有的键值。
还有一个想法是,如果album_id
是自己的候选键(它是唯一的),那么只需将其作为album
的主键即可。您不需要在artist_id
中添加track
列,然后,如artist
知道track
的{{1}}。您也可以将其传递给其他子表(album
)。
当然,如果您使用played
作为track_id
的序号(它不是唯一的,每个album
可能有album
= 1),那么你应该坚持使用复合键,或者使用其他唯一约束来制作代理键。
主键上的默认值也很令人费解,因为它们只适用于第一次插入。