MySQL alter table gives unknown column error - mysql

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.

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.

Related

Replace the statement ON DUPLICATE KEY UPDATE

MySQL version 5.7, ONLY_FULL_GROUP_BY is enabled
Please tell me an effective way to solve the following problem: it is necessary to make an entry in the table only if there are no matches in the record for several fields. If there is a matching record, then we update it with new data.
The ON DUPLICATE KEY UPDATE statement does not suit me, because the type and uuid_session fields are not unique (for example, there may be several records with different type, but with the same uuid_session).
Here is an example of a fake-query to better understand my question:
INSERT INTO cameraStatus(time, uuid_session)
VALUES ('2022-12-14 16:01:00', '01234567-8901-2345-6789-012345678901')
ON DUPLICATE KEY UPDATE (type, uuid_session) = ("WORK", "55555555-8901-2345-6789-012345678901");
My table:
CREATE TABLE `cameraStatus` (
`id` int NOT NULL,
`camera_id` int NOT NULL DEFAULT '0',
`time` timestamp NOT NULL DEFAULT '2021-12-31 21:00:00',
`type` varchar(50) COLLATE utf8_unicode_ci NOT NULL DEFAULT 'INFO',
`message` mediumtext COLLATE utf8_unicode_ci,
`uuid_session` varchar(36) CHARACTER SET utf8mb3 COLLATE utf8_unicode_ci DEFAULT '01234567-8901-2345-6789-012345678901'
)

Foreign key rejected despite columns having different data types

I'm trying to set up two tables in a database, and add a foreign key between them. They're declared as follows:
CREATE TABLE `clothing` (
`name` varchar(26) COLLATE utf8_bin NOT NULL,
`image` varchar(64) COLLATE utf8_bin NOT NULL,
`localized_name` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL CHECK (json_valid(`localized_name`)),
`main` varchar(18) COLLATE utf8_bin DEFAULT NULL,
`stars` tinyint(3) unsigned NOT NULL,
`id` tinyint(3) unsigned NOT NULL,
`splatnet` smallint(5) unsigned NOT NULL,
PRIMARY KEY (`splatnet`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
CREATE TABLE `abilities` (
`name` varchar(18) COLLATE utf8_bin DEFAULT NULL,
`image` varchar(48) COLLATE utf8_bin NOT NULL,
`id` tinyint(3) unsigned NOT NULL,
`localized_name` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL CHECK (json_valid(`localized_name`))
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
I want to create a foreign key on clothing that references abilities with the following command:
ALTER TABLE `abilities` ADD FOREIGN KEY (`name`) REFERENCES `clothing` (`main`);
However, attempting to do this raises this error in return:
Source and target columns must have the same data type, there must be an index on the target columns and referenced data must exist.
Can't create table `prismarine_rusted`.`abilities` (errno: 150 "Foreign key constraint is incorrectly formed")
I'm not entirely sure what's causing this, and unless I'm overlooking something really obvious, main and name have the same type, and therefore, should be able to be tied together via a foreign key. I'm using MariaDB v10.4.12, with SQL mode set to TRADITIONAL.
Although the foreign and primary key columns involved here are the same type, you are trying to reference clothing.main, which is not a unique or primary key column. From the MariaDB documentation:
The referenced columns must be a PRIMARY KEY or a UNIQUE index.
Note that this differs from InnoDB on MySQL, where a foreign key column can in fact reference a non unique column in another table.
One way to remedy this error would be to make clothing.main a unique column:
ALTER TABLE clothing ADD UNIQUE (main);
Note that doing this might only make logical sense if the values in main are already unique. If not, then perhaps you would have to revisit your data model.
It might be because there is a value in abilities.name that has no match in the referenced table.

Altering collation on field causes UNIQUE constraint to fail

When trying to alter my table with:
ALTER TABLE segment_item
CHANGE value value VARCHAR(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL;
I'm running into a UNIQUE constraint violation:
MySQLIntegrityConstraintViolationException: Duplicate entry for key 'segment_id'
Why would this be? This alteration to the table isn't adding a new record, it's just changing the character set and collation of existing records. For full visibility, here's the structure of the table:
CREATE TABLE `segment_item` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`value` varchar(100) COLLATE latin1_bin DEFAULT NULL,
`segment_id` binary(16) DEFAULT NULL,
`item_order` int(11) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `segment_id` (`segment_id`,`value`),
KEY `value` (`value`),
CONSTRAINT `segment_item_ibfk_1` FOREIGN KEY (`segment_id`) REFERENCES `segment` (`segment_id`)
) ENGINE=InnoDB AUTO_INCREMENT=36484 DEFAULT CHARSET=latin1 COLLATE=latin1_bin
The collation is how the db engine determines when records are unique. Looks like here you're changing from a binary collation (literally unique if and only if the bytes of the string are unique) to case insensitive unicode (which is case insensitive, but also uses a list of standard transformations to normalize digraphs, code point orders, etc).
So, for example, the following two strings used to be unique before your change (é is valid Latin-1):
Beyoncé
beyonce
But after the change they would be considered identical. My guess is that you have at least two "value"... er... values that are no longer unique under the new collation.

SQLError:Can't DROP Index_name; check that column/key exists -- occurs multiple times

I want to execute a alter command on a table, create table and alter table commands are as below.
CREATE TABLE `xyz` (
`entity_id` int(11) NOT NULL AUTO_INCREMENT,
`masterform_id` int(11) NOT NULL DEFAULT '1',
`app_status` varchar(500) DEFAULT NULL,
`NegativeMarks` decimal(15,5) DEFAULT NULL,
`ActualScore` decimal(15,5) DEFAULT NULL,
`RawScore` decimal(15,5) DEFAULT NULL,
`PANProratedMarks` decimal(15,5) DEFAULT NULL,
`PANNormalizedMarks` decimal(15,5) DEFAULT NULL,
`RRBZoneNormalizedMarks` decimal(15,5) DEFAULT NULL,
`RRBZoneProratedMarks` decimal(15,5) DEFAULT NULL,
`RRBZoneAllocationTempStorage` varchar(200) DEFAULT NULL,
`GraduatePercentage` decimal(15,5) DEFAULT NULL,
`PANAllocationTempStorage` varchar(1500) DEFAULT NULL,
PRIMARY KEY (`entity_id`),
UNIQUE KEY `app_seq_no` (`app_seq_no`),
UNIQUE KEY `ParticipantID` (`ParticipantID`),
UNIQUE KEY `RegistrationNo` (`RegistrationNo`),
KEY `idx_PANNormalizedMarks` (`PANNormalizedMarks`),
KEY `idx_RRBZoneNormalizedMarks` (`RRBZoneNormalizedMarks`)
) ENGINE=InnoDB AUTO_INCREMENT=273252 DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC
Alter table xyz
modify column ActualScore decimal(15,5),
modify column app_status varchar(500),
add index CalculatedCategory(CalculatedCategory),
modify column GraduatePercentage decimal(15,5),
modify column NegativeMarks decimal(15,5),
modify column PANAllocationTempStorage varchar(1500),
modify column PANNormalizedMarks decimal(15,5),
modify column PANProratedMarks decimal(15,5),
drop index idx_ParticipantID,
add unique ParticipantID(ParticipantID),
modify column RawScore decimal(15,5),
drop index idx_RegistrationNo,
add unique RegistrationNo(RegistrationNo),
modify column RRBZoneNormalizedMarks decimal(15,5),
modify column RRBZoneProratedMarks decimal(15,5);
I am getting this error:
SQLError:Can't DROP 'idx_ParticipantID'; check that column/key exists
But I am getting this same 104 times. Could you please let me know why am I getting this error 104 times in log? If the index doesnt exist it should just give the error once, please correct me if I am wrong.
After creating table xyz, you are supposed to create the wanted indexes, one of them is idx_ParticipantID (an index on the column ParticipantID). But you didn't create that one, that's why you can't drop it.
But you can ignore those errors, they have no effect on your database.
I advise you to read here some about indexes.

Is there any point of using COLLATE per column when creating tables?

I just did an export of a MySQL database in order to duplicate it on another server. Looking at the sql script I see the following:
CREATE TABLE `X` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL,
`email` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL
PRIMARY KEY (`id`),
KEY `name_index` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=8366
DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
Do I need to use this per column when collate is set for the table?
I think the reason for why each column has this, was because I wanted to make sure I could store locale values such as æ, ø å.
Since your column-level collations are all the same, setting the collation at the table level will have the same effect.
Note that collation has no effect on what you can store; rather, it affects how the results are sorted. The only reason you would want a different collation per column would be if your table contains columns with data for different locales requiring a different sort order.