外键创建失败的五大原因:一、被引用列非主键或唯一键;二、数据类型与长度不匹配;三、表引擎不一致(须均为innodb);四、字符集或排序规则不同;五、父表未先创建。

外键引用主键时总报错,插入失败、删除卡住、建表直接被拒,根本原因是新手对参照完整性规则理解不深,没意识到外键不是“随便指一个字段”就能生效的。
错误一:被引用列不是主键或唯一键
MySQL(InnoDB)要求外键必须引用目标表中的 PRIMARY KEY 或带有 UNIQUE 约束的索引列。如果只在 users 表里建了个普通字段 user_code,又试图让 orders.user_code 外键指向它,就会触发 errno: 150。
执行 SHOW CREATE TABLE users; 查看 user_code 是否带 KEY 或 UNIQUE 标识——没有就立刻补上:ALTER TABLE users ADD UNIQUE (user_code);
【必须先确认被引用列已建立唯一性保障,否则外键创建必然失败】
错误二:数据类型与长度完全不匹配
方法一:用 SHOW COLUMNS FROM users LIKE 'id'; 和 SHOW COLUMNS FROM orders LIKE 'user_id'; 对比两列定义。
常见坑点:users.id 是 INT(10) UNSIGNED,而 orders.user_id 写成 INT(10) SIGNED 或 BIGINT,哪怕只差一个符号位,MySQL 就拒绝建外键。
方法二:直接用 CAST 强制统一——但仅限调试,正式环境必须 ALTER TABLE orders MODIFY user_id INT UNSIGNED;
错误三:两张表引擎不一致
MyISAM 不支持外键约束。哪怕语法全对,只要其中一张表是 MyISAM,CREATE TABLE 就会静默忽略 FOREIGN KEY 子句,或报错 #1005。
查引擎:SELECT ENGINE FROM information_schema.TABLES WHERE TABLE_SCHEMA = 'your_db' AND TABLE_NAME = 'orders';
统一改用 InnoDB:ALTER TABLE orders ENGINE = InnoDB;
错误四:字符集或排序规则不一致
第一步:查 users 表字段字符集
SHOW FULL COLUMNS FROM users WHERE Field = 'email';
第二步:查 orders 表中对应外键字段
SHOW FULL COLUMNS FROM orders WHERE Field = 'user_email';
第三步:若发现一个是 utf8mb4_unicode_ci,另一个是 utf8mb4_general_ci,哪怕只是排序规则不同,也会导致外键创建失败。
修复命令:ALTER TABLE orders MODIFY user_email VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
错误五:父表未建好就急着建子表
外键依赖关系有严格顺序:父表(被引用表)必须存在且结构稳定后,子表才能成功建立外键约束。
典型翻车场景:迁移脚本里把 CREATE TABLE orders 放在 CREATE TABLE users 前面,运行时直接报错 “ERROR 1005: Can't create table”。
这一步操作起来很简单,直接把建 users 表的 SQL 放到 orders 表之前就行。











