Search code examples
mysqlalter-tablealter

MySQL alter table gives unknown column error


I'm renaming a bunch of columns in a lot of my tables and changing their data types for a major system update, and I haven't had many issues except for this one.

Error Code: 1054. Unknown column 'FactoryID' in 'factories'

show create table `factories`;
CREATE TABLE `factories` (
   `FactoryID` char(36) COLLATE utf8mb4_unicode_ci NOT NULL,
   `ParentFactoryID` char(36) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
   `Name` varchar(256) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
   `Notes` varchar(1024) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
   `DateTimeAdded` datetime DEFAULT NULL,
   `CountryID` smallint(5) unsigned NOT NULL,
   `ListID` varchar(64) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
   `Deleted` int(1) DEFAULT '0',
   PRIMARY KEY (`FactoryID`),
   UNIQUE KEY `FactoryID` (`FactoryID`),
   KEY `ParentFactoryID` (`ParentFactoryID`),
   KEY `CountryID` (`CountryID`),
   CONSTRAINT `factories[CountryID]` FOREIGN KEY (`CountryID`) REFERENCES `countries` (`CountryID`)
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

ALTER TABLE `sterling`.`factories` 
CHANGE COLUMN `CountryID` `CountryID` SMALLINT(5) UNSIGNED NOT NULL AFTER `FactoryID`,
CHANGE COLUMN `ParentFactoryID` `_OriginalFactoryID` CHAR(36) CHARACTER SET 'utf8mb4' COLLATE 'utf8mb4_unicode_ci' NULL DEFAULT NULL AFTER `ListID`,
CHANGE COLUMN `DateTimeAdded` `__Added` TIMESTAMP(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) AFTER `__Active`,
CHANGE COLUMN `Deleted` `__Active` TINYINT(1) NOT NULL DEFAULT 1 ,
ADD COLUMN `__Updated` TIMESTAMP(6) NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP(6) AFTER `__Added`,
drop primary key,
change column`FactoryID` `@FactoryID`char(36)null after`__Updated`,
add column`FactoryID`binary(8)not null first,
add index`@FactoryID`(`@FactoryID`);

Am I missing an order of operations sort of thing? If all of those changes happen in order, I'm not sure what exactly the problem is, since at no time that FactoryID is referenced does it not exist.


Solution

  • The columnname that after refers to is supposed to be the new name of the column in the final table. It doesn't matter where in the statement you change the name.

    And it actually even makes this following statement fail:

    alter table tablename
    add column b int after a,
    drop column a 
    

    Error Code: 1054. Unknown column 'a' in 'tablename'

    as in the final table, there will be no column a anymore, so it is invalid even if you drop a only after you already added column b.

    In your case, you would need to change

    CHANGE COLUMN `CountryID` `CountryID` ... AFTER `FactoryID`,
    

    to

    CHANGE COLUMN `CountryID` `CountryID` ... AFTER `@FactoryID`,
    

    in order to anticipate that you will (later) rename the column FactoryID to @FactoryID.

    To make it complete: in after, you cannot refer to a column that you will add later. For example, in the end of your statement, you actually add another column FactoryID, but you cannot yet refer to it here (otherwise, the query would not have failed). You could add that column first though (and even before you rename the original FactoryId, MySQL allows you to swap columnnames that way). CHANGE COLUMN CountryID CountryID ... AFTER FactoryID would then work, but would refer to the new column (so in total, CountryID would be the 2nd column, which may or may not be what you intended).

    I don't know if it is officially documented somewhere, you will probably have to take it as convention, but it has "always" been that way.