在获取MySQL代码时出现错误1215和1146

时间:2013-04-04 19:19:16

标签: mysql sql

我正在研究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。我一直在考虑这个问题。什么似乎是错的?

2 个答案:

答案 0 :(得分:1)

您的代码失败的原因是因为您在albumtrack表上有一个复合主键。 为了允许成功创建外键,必须为复合键的每一列的每个表添加另一个索引。

尝试修改每个表的代码以添加索引,如下所示。 在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),那么你应该坚持使用复合键,或者使用其他唯一约束来制作代理键。

主键上的默认值也很令人费解,因为它们只适用于第一次插入。