[英]Error when creating foreign key of type CHAR with mysql workbench: Error 1005: Can't create table (errno: 150)
I have defined the following 2 tables:我定义了以下 2 个表:
record_status记录状态
SHOW CREATE TABLE record_status显示创建表记录状态
CREATE TABLE `record_status` (
`record_status_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`status` char(6) NOT NULL,
`status_description` varchar(15) NOT NULL,
`created_at` datetime NOT NULL,
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`record_status_id`,`status`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1
user用户
SHOW CREATE TABLE user显示创建表用户
CREATE TABLE `user` (
`user_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`handle` varchar(45) NOT NULL,
`email` varchar(255) NOT NULL,
`password` char(64) DEFAULT NULL,
`password_salt` binary(1) DEFAULT NULL,
`first_name` varchar(50) NOT NULL,
`last_name` varchar(50) NOT NULL,
`gender` char(1) DEFAULT NULL,
`birthday` date NOT NULL,
`created_at` datetime NOT NULL,
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`user_status` char(6) DEFAULT NULL,
PRIMARY KEY (`user_id`),
KEY `usr_status_idx` (`user_status`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
and I tried adding the foreign key user_status of type CHAR using mysql Workbench as follows:我尝试使用 mysql Workbench 添加 CHAR 类型的外键 user_status ,如下所示:
ALTER TABLE `mydatabase`.`user`
ADD CONSTRAINT `usr_status`
FOREIGN KEY (`user_status`)
REFERENCES `mydatabase`.`record_status` (`status`)
ON DELETE NO ACTION
ON UPDATE NO ACTION;
but I am getting the following error:但我收到以下错误:
Error :错误:
Executing SQL script in server
ERROR: Error 1005: Can't create table 'mydatabase.#sql-420_1b0' (errno: 150)
ALTER TABLE 'mydatabase'.'user'
ADD CONSTRAINT 'usr_status'
FOREIGN KEY ('user_status')
REFERENCES 'mydatabase'.'record_status'('status')
ON DELETE NO ACTION
ON UPDATE NO ACTION
SQL script execution finished: statements: 4 succeeded, 1 failed.
Question题
My intention is to have the status column clearly show the current status for each user (ACTIVE, INACTV, DELETD) while still having the flexibility to join the record_status table with the user table using the record_status_id to find any rows with a given status for better performance.我的目的是让状态列清楚地显示每个用户的当前状态(ACTIVE、INACTV、DELETD),同时仍然可以灵活地使用 record_status_id 将 record_status 表与用户表连接起来,以更好地查找具有给定状态的任何行表现。
I found a similar post here Adding foreign key of type char in mysql which suggests to change my primary key's collation but, how would that affect my user table?我在这里找到了一个类似的帖子在 mysql 中添加 char 类型的外键,它建议更改我的主键的排序规则,但是,这将如何影响我的用户表?
Will I have to change the collation to the user_status field in my user table as well?我是否也必须将排序规则更改为用户表中的 user_status 字段? The user table will be queried every time a user logs in and I am concerned about performance or any constraints this may cause.
每次用户登录时都会查询用户表,我担心性能或这可能导致的任何限制。
I also intend to add a foreign key for the status to a few other tables as well.我还打算将状态的外键添加到其他几个表中。 I would just like to know how this affects performance, or does it add any constraints?
我只想知道这如何影响性能,或者它是否增加了任何限制?
Any input regarding my design will also be appreciated.任何有关我的设计的意见也将不胜感激。 Thank you for your help!
感谢您的帮助!
The issue you're facing isn't actually related to collation (though collation can be a cause of the error you're experiencing under different circumstances).您面临的问题实际上与整理无关(尽管整理可能是您在不同情况下遇到错误的原因)。
Your FOREIGN KEY
constraint is failing because you don't have an index individually on record_status.status
.您的
FOREIGN KEY
约束失败,因为您在record_status.status
上没有单独的索引。 You have that column as part of the composite PRIMARY KEY (record_status_id, status)
, but for successful foreign key constraint creation, both the referencing table and the referenced table must have indexes on exactly the columns used in the key relationship (in addition to the same data types).您有列作为复合材料的一部分
PRIMARY KEY (record_status_id, status)
,但对于外键约束创建成功,无论是引用表和引用表必须有准确的关键关系中使用的列的索引(除相同的数据类型)。
Adding the FOREIGN KEY
constraint implicitly creates the necessary index on the referencing table, but you must still ensure you have the corresponding index on the referenced table.添加
FOREIGN KEY
约束会隐式地在引用表上创建必要的索引,但您仍必须确保在被引用表上具有相应的索引。
So given what you have now, if you added a single index on record_status.status
, the constraint would correctly be created.因此,鉴于您现在拥有的情况,如果您在
record_status.status
上添加了单个索引,则将正确创建约束。
CREATE TABLE `record_status` (
`record_status_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`status` char(6) NOT NULL,
`status_description` varchar(15) NOT NULL,
`created_at` datetime NOT NULL,
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`record_status_id`,`status`),
-- This would make your relationship work...
KEY (`status`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1
However, I don't think that's the best course of action.但是,我认为这不是最好的做法。 I don't see a need for the composite primary key on
(record_status_id, status)
, chiefly because the record_status_id
is itself AUTO_INCREMENT
and guaranteed to be unique.我认为
(record_status_id, status)
上不需要复合主键,主要是因为record_status_id
本身就是AUTO_INCREMENT
并且保证是唯一的。 That column alone could be the PRIMARY KEY
, while still adding an additional UNIQUE KEY
on status
to satisfy the foreign key constraint's indexing requirement.该列本身可以是
PRIMARY KEY
,同时仍然在status
上添加一个额外的UNIQUE KEY
以满足外键约束的索引要求。 After all, it is not the combination of record_status_id
and status
which uniquely identifies each row (making a primary key)毕竟,不是
record_status_id
和status
的组合唯一标识每一行( record_status_id
键)
CREATE TABLE `record_status` (
`record_status_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`status` char(6) NOT NULL,
`status_description` varchar(15) NOT NULL,
`created_at` datetime NOT NULL,
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
-- Primary only on record_status_id
PRIMARY KEY (`record_status_id`),
-- Additional UNIQUE index on status
UNIQUE KEY (`status`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1
record_status_id
...record_status_id
... Without knowing how the rest of your application currently uses record_status_id
, I can't say for sure if it required by your application code.在不知道您的应用程序的其余部分当前如何使用
record_status_id
,我无法确定您的应用程序代码是否需要它。 But, if you wish to make the actual status
value easily available to other tables, and it is merely CHAR(6)
, it is possible that you actually have no need for record_status_id
as an integer value.但是,如果您希望让其他表轻松获得实际
status
值,并且它只是CHAR(6)
,则您实际上可能不需要将record_status_id
作为整数值。 After all, if the status
string is intended to be unique, then it is perfectly capable of serving as the PRIMARY KEY
on its own, without any auto-increment integer key.毕竟,如果
status
字符串是唯一的,那么它完全可以单独用作PRIMARY KEY
,而无需任何自动递增的整数键。
In that case, your record_status
table would look like below, and your FOREIGN KEY
constraint would correctly be added to users
.在这种情况下,您的
record_status
表将如下所示,并且您的FOREIGN KEY
约束将正确添加到users
。
CREATE TABLE `record_status` (
-- Remove the auto_increment column!!
`status` char(6) NOT NULL,
`status_description` varchar(15) NOT NULL,
`created_at` datetime NOT NULL,
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
-- Status is unique, and therefore can be the PK on its own
PRIMARY KEY (`status`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1
Given this setup, here's a sample showing the successful creation of the tables and addition of the FK constraint.鉴于此设置,以下示例显示成功创建表和添加 FK 约束。
You asked about performance implications of adding a status FK to other tables as well.您还询问了向其他表添加状态 FK 的性能影响。 It's tough to speculate on that without knowing the purpose, but if other tables share the same
status
values, then it makes sense to create their FK constraints to link to it in the same say you're doing with users
.在不知道目的的情况下很难推测,但如果其他表共享相同的
status
值,那么创建它们的 FK 约束以链接到它是有意义的,就像你对users
所做的一样。 And if that's the case, I would recommend doing it the same way, wherein the status
column is CHAR(6)
(or consider changing all of them to VARCHAR(6)
).如果是这种情况,我会建议以相同的方式执行此操作,其中
status
列是CHAR(6)
(或考虑将它们全部更改为VARCHAR(6)
)。 The value of record_status.status
still makes sense as the true primary key, and can be used as the FK in as many related tables as necessary. record_status.status
的值作为真正的主键仍然有意义,并且可以根据需要在尽可能多的相关表中用作 FK。
In all but the most gigantic scale, there should be no appreciable performance difference between using an INT
value and a CHAR(6)/VARCHAR(6)
value as the foreign key.除了最大的规模之外,在使用
INT
值和使用CHAR(6)/VARCHAR(6)
值作为外键之间应该没有明显的性能差异。 And the storage size difference between them is equally tiny.并且它们之间的存储大小差异同样很小。 It isn't worth worrying about unless you must scale this to positively enormous proportions.
除非您必须将其扩展到非常大的比例,否则不值得担心。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.