【问题标题】:MySQL: Creating a table that with a foreign key that references a primary key made up of foreign keysMySQL:创建具有引用由外键组成的主键的外键的表
【发布时间】:2015-02-06 20:28:48
【问题描述】:

我有一个书籍表,其中存储书籍 ID 和标题、作者等,还有一个包含客户 ID (PK)、客户姓名、生日的客户表。然后是一个事务表,其中包括 BookId 和 CustomerID 作为外键。这个事务表的主键是两个外键列。

现在的问题是我正在创建一个基于已发生交易的图书评级表(因此客户无法对他们不拥有的图书或同一本书进行两次评级。)。此表必须包含 bookID、customerID 和评级信息。我试图约束表,以便每个 bookID 和 customerID 行都必须引用事务表中的现有行。但是,到目前为止,我尝试过的所有限制都不起作用。任何帮助都将不胜感激。

这是我现在的桌子:

CREATE TABLE eBook
 (      BookTitle   VARCHAR(50),
    BookID      CHAR(13) NOT NULL,
    BookPub     CHAR(4) NOT NULL,
    BookDate    DATE NOT NULL,
    BookHard    BOOL NOT NULL,
    BookSize    INT NOT NULL, 
CONSTRAINT PKBookID PRIMARY KEY (BookID)
);

CREATE TABLE customer
(       CustID      CHAR(9) NOT NULL,
    CustSSN     CHAR(11) NULL,
    CustName    VARCHAR(50) NOT NULL,
    CustBirth   INT(4) NOT NULL, 
CONSTRAINT PKCustID PRIMARY KEY (CustID),
CONSTRAINT UniqSSN UNIQUE (CustSSN)
);

CREATE TABLE Buys
(   BuysID      CHAR(5) NOT NULL                    
BookID      CHAR(13) NOT NULL,
CustID      CHAR(9) NOT NULL,
TransDate   DATETIME NOT NULL,
Price       DECIMAL(5,2) NOT NULL,
CONSTRAINT FK1 FOREIGN KEY (BookID) REFERENCES eBook (BookID)
ON DELETE CASCADE
ON UPDATE CASCADE,
CONSTRAINT FK2 FOREIGN KEY (CustID) REFERENCES customer (CustID)
ON DELETE CASCADE
ON UPDATE CASCADE,
CONSTRAINT PKBuys PRIMARY KEY (BookID, CustID)
);

CREATE TABLE Rating
(   BookID      CHAR(13) NOT NULL,
CustID      CHAR(9) NOT NULL,
RatingID    CHAR(5) NOT NULL,
Rating      INT(1) NOT NULL,
RatingDate  DATE NOT NULL,
CONSTRAINT FK13 FOREIGN KEY (BookID, CustID) REFERENCES buys (BookID, CustID)
ON DELETE CASCADE
ON UPDATE CASCADE,
CONSTRAINT PKRating PRIMARY KEY (RatingID)
);

【问题讨论】:

  • 不要忘记将您尝试过的内容添加到您的问题中(如在实际创建表或查询中或任何可能的内容中),以便人们可以轻松地帮助您。
  • 虽然有些人会认为这不是最正确的方法,但我会做的只是将评级列添加到 Buys 表中。这样,用户可以对购买或不购买进行评分,但他们只能对自己的购买进行评分。
  • Buys 表中使用自增ID 作为主键,并在Rating 表中使用它作为外键可能会更好。您仍然可以在 (BookID, CustID) 上拥有唯一密钥,以防止重复购买。

标签: mysql database


【解决方案1】:

您的Rating 表上已经有一个外键,该外键应将每个Rating 行限制为对应于Buys 行。我想问题一定出在您的另一个目标上,即客户不能对同一本书进行两次评分。关于这一点,我猜你对外键有一个误解:它们在 target 表上必须是唯一的,但它们在引用端不一定必须是唯一的。

为防止多个Rating 行具有相同的BookIDCustomerID 组合,您需要在Rating 表上附加一个UNIQUE 约束,命名这些列。或者,您可以为Rating 表提供一个由这些列组成的复合主键。无论哪种方式,您都将有单独的约束,一个确定引用表中这些列的唯一性,另一个将它们限制为出现在 Buys 表中的对。

【讨论】:

    【解决方案2】:

    您可以创建一个多列外键引用,如 http://dev.mysql.com/doc/refman/5.0/en/create-table-foreign-keys.html 中所述 这应该可以解决问题。

    您的示例代码包含错误。您在 Buys 表中缺少一个 (,)。

    CREATE TABLE eBook
     (      BookTitle   VARCHAR(50),
        BookID      CHAR(13) NOT NULL,
        BookPub     CHAR(4) NOT NULL,
        BookDate    DATE NOT NULL,
        BookHard    BOOL NOT NULL,
        BookSize    INT NOT NULL, 
    CONSTRAINT PKBookID PRIMARY KEY (BookID)
    );
    
    CREATE TABLE customer
    (       CustID      CHAR(9) NOT NULL,
        CustSSN     CHAR(11) NULL,
        CustName    VARCHAR(50) NOT NULL,
        CustBirth   INT(4) NOT NULL, 
    CONSTRAINT PKCustID PRIMARY KEY (CustID),
    CONSTRAINT UniqSSN UNIQUE (CustSSN)
    );
    
    CREATE TABLE Buys
    (   BuysID      CHAR(5) NOT NULL,                   
    BookID      CHAR(13) NOT NULL,
    CustID      CHAR(9) NOT NULL,
    TransDate   DATETIME NOT NULL,
    Price       DECIMAL(5,2) NOT NULL,
    CONSTRAINT FK1 FOREIGN KEY (BookID) REFERENCES eBook (BookID)
    ON DELETE CASCADE
    ON UPDATE CASCADE,
    CONSTRAINT FK2 FOREIGN KEY (CustID) REFERENCES customer (CustID)
    ON DELETE CASCADE
    ON UPDATE CASCADE,
    CONSTRAINT PKBuys PRIMARY KEY (BookID, CustID)
    );
    
    CREATE TABLE Rating
    (   BookID      CHAR(13) NOT NULL,
    CustID      CHAR(9) NOT NULL,
    Rating      INT(1) NOT NULL,
    RatingDate  DATE NOT NULL,
    CONSTRAINT FK13 FOREIGN KEY (BookID, CustID) REFERENCES buys (BookID, CustID)
    ON DELETE CASCADE
    ON UPDATE CASCADE,
    CONSTRAINT PKRating PRIMARY KEY (BookID, CustID)
    );
    

    当使用这个更正的 ddl 时,表格创建得很好。

    我已经创建了一些测试数据

    insert into `ebook`(`BookTitle`,`BookID`,`BookPub`,`BookDate`,`BookHard`,`BookSize`) values ('grey','1','ME','2015-02-06',1,10);
    insert into `customer`(`CustID`,`CustSSN`,`CustName`,`CustBirth`) values ('1','daCust','Cust',1974);
    insert into `buys`(`BuysID`,`BookID`,`CustID`,`TransDate`,`Price`) values ('1','1','1','2015-02-06 00:00:00',10.00);
    insert into `rating`(`BookID`,`CustID`,`RatingID`,`Rating`,`RatingDate`) values ('1','1','1',1,'2015-02-06');
    

    现在添加以下数据会因为外键约束而报错。

    insert into `rating`(`BookID`,`CustID`,`RatingID`,`Rating`,`RatingDate`) values ('7','3','1',1,'2015-02-06');
    

    为确保用户只能为每本书添加一个评分,您应该在字段 BookID 和 CustID 上添加唯一约束,或者将这些字段设置为主键。在上面的工作代码示例中,我将这些字段添加为主键并删除了过时的 RatingID。

    【讨论】:

    • 请在您的答案中包含资源中的相关信息。仅链接的答案可能会过时。
    • 谢谢,我确实在收视率表上试过了,但由于某种原因,它没有得到适当的限制。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-23
    • 1970-01-01
    • 2021-12-30
    • 1970-01-01
    • 2018-10-14
    • 1970-01-01
    相关资源
    最近更新 更多