如果FK表具有复合主键(FK不是复合键的一部分),则外键作为主键不起作用

时间:2013-01-31 07:14:34

标签: mysql foreign-keys primary-key foreign-key-relationship composite-primary-key

使用这些脚本创建的两个表:

create table user_auth
(
    username varchar(255) NOT NULL,
    password varchar(255) NOT NULL,
    user_id varchar(36) NOT NULL,
    PRIMARY KEY(username, password)
)engine=innodb;

create table user
(
    user_id varchar(36) NOT NULL,
    PRIMARY KEY(user_id),
    FOREIGN KEY(user_id) REFERENCES user_auth(user_id) ON DELETE CASCADE
)engine=innodb;

我收到错误:     无法创建表'xxx.user'(错误号:150)

外键错误。

IF代替我执行此操作(删除外键约束但仍引用user_auth):

create table user_auth
(
    username varchar(255) NOT NULL,
    password varchar(255) NOT NULL,
    user_id varchar(36) NOT NULL,
    PRIMARY KEY(username, password)
)engine=innodb;

create table user
(
    user_id varchar(36) NOT NULL REFERENCES user_auth(user_id) ON DELETE CASCADE,
    PRIMARY KEY(user_id),
)engine=innodb;

一切都很好, 但是 我可以在user_auth中插入user_id,而不会在user_auth中输入相应的密钥,这会在我的参照完整性中造成漏洞。< / p>

现在我要这样做(删除复合键并将user_id设为user_auth中的主键):

create table user_auth
(
    user_id varchar(36) NOT NULL,
    PRIMARY KEY(username, password)
)engine=innodb;

create table user
(
    user_id varchar(36) NOT NULL,
    PRIMARY KEY(user_id),
    FOREIGN KEY(user_id) REFERENCES user_auth(user_id) ON DELETE CASCADE
)engine=innodb;

这也有效,但我没有用户名/密码复合以确保唯一性。

我有一种感觉,我错过了MySQL如何工作的关键。请指教。

谢谢你的时间!

更新

在他们的答案中链接的文章ypercube中,第三点提到PK的 顺序 ,相应的FK 必须相同。如果我按以下顺序在user_id中添加user_auth作为PK,则脚本可以正常运行:

create table user_auth
(
    username varchar(255) NOT NULL,
    password varchar(255) NOT NULL,
    user_id varchar(36) NOT NULL,
    PRIMARY KEY(user_id, username, password)
)engine=innodb;

create table user
(
    user_id varchar(36) NOT NULL,
    PRIMARY KEY(user_id),
    FOREIGN KEY(user_id) REFERENCES user_auth(user_id) ON DELETE CASCADE
)engine=innodb;

所以我仍然可以SELECT等,但现在我不能制作重复的用户名/密码组合,因此每个帐户都是唯一的,因为在插入用户数据之前必须存在用户名/密码/ user_id记录。

2 个答案:

答案 0 :(得分:1)

尝试:

create table user_auth
(
    username varchar(255) NOT NULL,
    password varchar(255) NOT NULL,
    user_auth_id varchar(36) NOT NULL,
    PRIMARY KEY(username, password)
)engine=innodb;

create table user
(
    user_id varchar(36) NOT NULL,
    user_username varchar(36) NOT NULL, 
    user_pass varchar(36) NOT NULL, 
    INDEX(user_username, user_pass),
    PRIMARY KEY(user_id),
    FOREIGN KEY(user_username, user_pass) REFERENCES user_auth(username, password) ON DELETE CASCADE
)engine=innodb;

参考:http://dev.mysql.com/doc/refman/5.5/en/innodb-foreign-key-constraints.html

答案 1 :(得分:1)

http://dev.mysql.com/doc/refman/5.5/en/innodb-foreign-key-constraints.html中的第3点说明了一切。因此,如果我在user_id中添加user_auth作为PK(我想我提到过我试过这个,但似乎我错过了脚本示例),那么它仍然可能无效:

create table user_auth
(
    username varchar(255) NOT NULL,
    password varchar(255) NOT NULL,
    user_id varchar(36) NOT NULL,
    PRIMARY KEY(username, password, user_id) -- <== DOES NOT WORK
)engine=innodb;

create table user
(
    user_id varchar(36) NOT NULL,
    PRIMARY KEY(user_id),
    FOREIGN KEY(user_id) REFERENCES user_auth(user_id) ON DELETE CASCADE
)engine=innodb;

但是,如果我改变订单......

create table user_auth
(
    username varchar(255) NOT NULL,
    password varchar(255) NOT NULL,
    user_id varchar(36) NOT NULL,
    PRIMARY KEY(user_id, username, password) -- <== WORKS!
)engine=innodb;

create table user
(
    user_id varchar(36) NOT NULL,
    PRIMARY KEY(user_id),
    FOREIGN KEY(user_id) REFERENCES user_auth(user_id) ON DELETE CASCADE
)engine=innodb;

因为为了将user_auth的PK用作FK,它们必须是与索引相同的顺序,(如果我误解了某些内容,请发表评论)。

但就表格设计而言,我们仍有问题,复合键意味着我可能在user_auth中有重复的user_id,因此更智能的设计将是:

create table user_auth
(
    username varchar(255) NOT NULL,
    password varchar(255) NOT NULL,
    user_id varchar(36) NOT NULL,
    PRIMARY KEY(user_id),
    UNIQUE KEY(username) -- <== I should allow duplicate passwords, so just usernames should be               unique
)engine=innodb;

create table user
(
    user_id varchar(36) NOT NULL,
    PRIMARY KEY(user_id),
    FOREIGN KEY(user_id) REFERENCES user_auth(user_id) ON DELETE CASCADE
)engine=innodb;

好多了

主要的好处是复合键的顺序 很重要!

相关问题