3

我正在阅读 O'Reilly 出版的“Learning 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');

但是,当我尝试SOURCEMySQL 时,它给了我ERROR 1215 (HY000): Cannot add foreign key constraintERROR 1146 (42s02): Table 'music.track' doesn't exist. 我一直在考虑这个问题。似乎有什么问题?

4

2 回答 2

1

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

尝试修改每个表的代码以添加索引,如下所示。在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)
);
于 2013-04-04T19:37:36.260 回答
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)
);

您必须在已播放的表中进行类似的更改。

这是这些更改的 SqlFiddle,包括以正确的顺序插入数据,以及现有的键值。

还有一种想法是,如果album_id它是自己的候选键(它是唯一的),那么只需将其设为album. 那么,正如您所知道的那样,您不需要将artist_id列放在中。您也可以对其他子表 ( ) 执行此操作。trackartisttrackalbumplayed

当然,如果您track_id在 an 上用作序数album(它不是唯一的,每个album可能都有 a track_id= 1),那么您应该坚持使用复合键,或者使用其他唯一约束来制作代理键。

考虑到它们仅适用于第一次插入,主键的默认值也令人费解。

于 2013-04-04T19:37:40.040 回答