在带有外键的 MySQL InnoDB 数据库中,我不小心对一些主键进行了签名,而不是像我希望的那样未签名。
现在我想用 ALTER TABLE 语句更改它,但它不起作用:
ALTER TABLE `users` CHANGE `id` `id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT
MySQL 错误:
Error on rename of './db_dev/#sql-478_3' to './db_dev/users' (errno: 150)
我不明白为什么。我正在使用外键并尝试使用
SET foreign_key_checks = 0;
执行上面的 ALTER TABLE 之前的语句。也不行。 注意:我所有的桌子仍然是空的。里面还没有数据。
由于数据库有很多表,删除所有外键然后再次手动添加它们将需要大量工作。 (如果这应该是原因的话)。
该字段用于外键。要更改 MySQL 中的此字段,您应该执行以下步骤:
我接手的一个项目,有相同的问题,一些主键被签名了,相关的外域也被签名了。
我使用了@Devart 方法,但我能够自动化整个过程。 我能够查询
information_schema
以生成其他 SQL 语句,我可以“剪切并粘贴”这些语句,然后运行。
生成 SQL 语句以删除所有约束
SELECT concat('ALTER TABLE ', TABLE_NAME, ' DROP FOREIGN KEY ', CONSTRAINT_NAME, ';')
FROM information_schema.key_column_usage
WHERE CONSTRAINT_SCHEMA = 'YOUR_SCHEMA_NAME'
AND referenced_table_name IS NOT NULL;
更改任何需要更改为 UNSIGNED 的
id
列
SELECT
CONCAT('ALTER TABLE `', TABLE_NAME, '` CHANGE COLUMN id id INT UNSIGNED NOT NULL AUTO_INCREMENT;')
FROM `COLUMNS`
WHERE
`COLUMN_KEY` = 'PRI' AND
`TABLE_SCHEMA` = 'YOUR_SCHEMA_NAME' AND
`COLUMN_TYPE` NOT LIKE '%unsigned%' AND
`COLUMN_TYPE` LIKE '%int%' AND
`COLUMN_NAME` = 'id';
更改指向
id
的外部字段
SELECT CONCAT('ALTER TABLE `', kcu.TABLE_NAME, '` CHANGE COLUMN ', kcu.COLUMN_NAME,' ', kcu.COLUMN_NAME, ' INT UNSIGNED ', IF(c.IS_NULLABLE = 'YES', 'NULL', 'NOT NULL'), ';')
FROM `KEY_COLUMN_USAGE` kcu
INNER JOIN `COLUMNS` c
ON
kcu.TABLE_NAME = c.TABLE_NAME AND
kcu.COLUMN_NAME = c.COLUMN_NAME
WHERE
`REFERENCED_COLUMN_NAME` = 'id' AND
`REFERENCED_TABLE_NAME` IN (
SELECT
TABLE_NAME
FROM `COLUMNS`
WHERE
`COLUMN_KEY` = 'PRI' AND
`TABLE_SCHEMA` = 'YOUR_SCHEMA_NAME' AND
`COLUMN_TYPE` NOT LIKE '%unsigned%' AND
`COLUMN_TYPE` LIKE '%int%' AND
`COLUMN_NAME` = 'id'
);
(注意此语句中,全部被错误修改为UNSIGNED 即使它们已经未签名,但这不会导致任何问题)
重新插入所有必需的约束
SELECT CONCAT('ALTER TABLE ', rc.`TABLE_NAME` ,' ADD CONSTRAINT ', rc.`CONSTRAINT_NAME`, ' FOREIGN KEY (',kcu.`COLUMN_NAME`,') REFERENCES ', rc.`REFERENCED_TABLE_NAME` ,'(id) ON DELETE ', DELETE_RULE , ' ON UPDATE ' , UPDATE_RULE, ';')
FROM `REFERENTIAL_CONSTRAINTS` rc
INNER JOIN
`KEY_COLUMN_USAGE` kcu
ON rc.CONSTRAINT_NAME = kcu.CONSTRAINT_NAME
WHERE kcu.CONSTRAINT_SCHEMA = 'api' AND
kcu.`REFERENCED_COLUMN_NAME` = 'id';
密切关注这些 SQL 语句,它可能需要根据您的架构进行修改,例如,它假设您的主 id 称为“id”。
此外,您必须在运行这些语句的任何实际输出之前运行所有 4 个语句。
使用MySQL 5.6
使用 mysql 命令 mysqldump 转储数据库,并在需要的每个位置搜索并添加未签名的位置。然后将转储恢复到同一数据库。在恢复之前,删除其中的所有表并将其转储。
试试这个
ALTER TABLE 'users' MODIFY 'id' UNSIGNED NOT NULL AUTO_INCREMENT'
MySQL Workbench 可以让您做到这一点。您需要确保更改主键以及每个具有外键引用的表中的所有列。
我发现它适用于多种场景,YMMV。
以下内容在许多情况下都适用,尽管这取决于列的修改方式
-- disable fk constraints
SET FOREIGN_KEY_CHECKS=0;
ALTER TABLE 'table' MODIFY 'column'....
-- re-enable fk constraints
SET FOREIGN_KEY_CHECKS=1;
如果它使 FK 无效,这可能不起作用 - 在这种情况下,您需要删除/重新创建 FK。
ALTER TABLE 'table' DROP FOREIGN KEY FK_xxxxxxxxxxx;
ALTER TABLE 'table' MODIFY 'column'....
ALTER TABLE 'table'
add constraint FK_xxxxxxxxxxx
foreign key ('key-column') references 'other table' ('key-column');