【问题标题】:How to change MySQL Primary Key from signed to unsigned?如何将 MySQL 主键从已签名更改为未签名?
【发布时间】:2012-05-31 12:22:33
【问题描述】:

在我的带有外键的 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 foreign-keys relational-database primary-key innodb


    【解决方案1】:

    此字段用于外键。要在 MySQL 中更改此字段,您应该执行以下步骤:

    • 删除所有相关的外键
    • 修改字段
    • 重新创建所有丢弃的外键

    【讨论】:

    【解决方案2】:

    使用 mysql 命令 mysqldump 对数据库进行转储,然后搜索并在需要的每个位置添加无符号。然后将转储还原到同一数据库。在恢复之前删除所有表并转储它。

    【讨论】:

    • 比删除外键简单得多。 (如果你能做到的话)
    • 不必重新创建所有外键为我节省了很多时间。
    • 这是最好的答案,不到一分钟(我需要删除未签名的)
    【解决方案3】:

    我接手的一个项目,有相同issue,部分主键被签名,相关的外域也被签名。

    我使用了@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

    【讨论】:

      【解决方案4】:

      试试这个
      ALTER TABLE 'users' MODIFY 'id' UNSIGNED NOT NULL AUTO_INCREMENT'

      【讨论】:

        【解决方案5】:

        MySQL Workbench 会让你这样做。您需要确保更改 PRIMARY KEY 以及每个具有外键引用的表中的所有列。

        我发现它适用于多种场景,YMMV。

        【讨论】:

          【解决方案6】:

          以下内容在许多情况下都有效,尽管这取决于列的修改方式

          -- 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');
          

          【讨论】:

          • 请添加一些解释,即使代码是解释性的。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2010-10-03
          • 2018-03-20
          • 2020-01-28
          • 2011-12-06
          • 1970-01-01
          相关资源
          最近更新 更多