【问题标题】:Error 1215 and 1146 When Sourcing MySQL Code采购 MySQL 代码时出现错误 1215 和 1146
【发布时间】:2013-04-04 19:19:15
【问题描述】:

我正在阅读 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');

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

【问题讨论】:

    标签: mysql sql


    【解决方案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 的主键。你不需要在track 中拥有artist_id 列,然后,正如你所知道的trackartistalbum 所组成。您也可以对其他子表 (played) 执行此操作。

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

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

    【讨论】:

    • 我在答案中添加了SqlFiddle,以显示这些更改。请注意,数据也应该以正确的顺序插入(艺术家然后专辑等)。
    • 我刚刚复制并粘贴了你的代码,它给了我Error 1452 (23000): Cannot add or update a child row: a foreign key constraint fails( music.played, ed_ibfk_1 FOREIGN KEY (artist-id) REFERENCES artist` (artist_id))
    • 我猜您正在使用自己的插入语句,它们是 A:乱序(父级之前的子级?)和 B:尝试将值插入父级中不存在的子表中表(即使它们的顺序正确)。请注意我在 SQL Fiddle 链接中使用的插入语句。
    • 你是对的!我什至不知道为什么作者发布了这样错误的代码(当然这本书并不便宜)。所以它起作用了,但我是一个初学者,我无法用外键、引用等来包裹我的脑袋。为什么我们需要引用整个候选键?
    • This wiki article 可能有关于原因的有用信息。
    【解决方案2】:

    您的代码失败的原因是因为您在 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)
    );
    

    【讨论】:

    • 这是否假定album.album_idtrack.track_id 都是唯一的?
    • 有趣。作为主要的 SQL Server 开发人员,reference something that's not unique 对我来说既有趣又害怕。
    • 我以为你问的是它是否被创建为唯一索引,而不是列本身是否包含唯一值。我想他们会这样做,尽管这不是我的设计。
    • 我个人不会使用复合主键,因为我会满足于为每个有问题的表使用唯一的 id 列。 OP 并没有询问有关数据库设计的建议,他只是问他为什么会收到这两条错误消息。
    • 您的代码也有效!但是这种方法与蒂姆的方法有什么不同呢?你的和他的有性能差异吗?我是 SQL 初学者,非常感谢您的意见。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-21
    • 2018-05-13
    • 2015-05-27
    • 2017-09-18
    • 2014-10-22
    相关资源
    最近更新 更多