unable to create a foreign key constraint in mysql - mysql

I am unable to create a foreign key constraint in mysql for the column "vsa", below is my table structure. i am getting error as "Error creating foreign key on vsa(check data types)". Here I don't see any issues with data type. What am i Missing.
CREATE TABLE `child` (
`id` int(11) NOT NULL,
`day` tinyint(3) NOT NULL,
`vsa` varchar(50) NOT NULL,
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `parent` (
`price_id` int(10) NOT NULL,
`device_id` text NOT NULL,
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`vsa` varchar(50) NOT NULL,
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
As an alternative approach I run the alter query to add a constraint. I am getting below error.
Cannot find an index in the referenced table where the
referenced columns appear as the first columns, or column types
in the table and the referenced table do not match for constraint.
Note that the internal storage type of ENUM and SET changed in
tables created with >= InnoDB-4.1.12, and such columns in old tables
cannot be referenced by such columns in new tables.
See http://dev.mysql.com/doc/refman/5.0/en/innodb-foreign-key-constraints.html
for correct foreign key definition. ```

Related

Foreign key constraint fails but referenced row exists

I'm running MySQL 5.7.21 on Amazon RDS.
I know this question has been asked a thousand times, but I'm getting the issue on a scenario I wouldn't expect, so please read through before downvoting or marking as duplicate.
I'm not restoring the database, just running single INSERT queries, so is not a matter of ordering.
The referenced row does exist on the table; me and my colleagues had it triple checked.
As one might expect, disabling the FK checks with SET foreign_key_checks = 0 does make the query work.
I've seen this happening because of different table charsets, but in this case, both use utf8mb4. Also both have collation set to utf8mb4_general_ci.
This is happening in a production environment, so dropping the tables and recreating them is something I would like to avoid.
Some additional information:
The FK constraint was created AFTER the original tables were already populated.
Here is the relevant portion of the current DDL:
CREATE TABLE `VehicleTickets` (
`id` varchar(50) NOT NULL,
`vehiclePlate` char(7) NOT NULL,
`organizationId` varchar(50) NOT NULL,
`createdAt` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updatedAt` timestamp NULL DEFAULT NULL,
`status` varchar(15) NOT NULL DEFAULT 'OPEN',
`description` text NULL DEFAULT NULL,
`ticketInfo` json DEFAULT NULL,
`externalId` varchar(100) GENERATED ALWAYS AS (json_unquote(json_extract(`ticketInfo`,'$.externalId'))) VIRTUAL,
`value` decimal(10,2) GENERATED ALWAYS AS (json_unquote(json_extract(`ticketInfo`,'$.value'))) VIRTUAL,
`issuedAt` timestamp GENERATED ALWAYS AS (json_unquote(json_extract(`ticketInfo`,'$.issuedAt'))) VIRTUAL NOT NULL,
`expiresAt` timestamp GENERATED ALWAYS AS (json_unquote(json_extract(`ticketInfo`,'$.expiresAt'))) VIRTUAL NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `VehicleTickets_externalId_unq_idx` (`externalId`,`organizationId`),
KEY `VehicleTickets_vehiclePlate_idx` (`vehiclePlate`),
KEY `VehicleTickets_organizationId_idx` (`organizationId`),
KEY `VehicleTickets_issuedAt_idx` (`createdAt`),
KEY `VehicleTickets_expiresAt_idx` (`expiresAt`),
CONSTRAINT `VehicleTickets_Organizations_fk`
FOREIGN KEY (`organizationId`) REFERENCES `Organizations` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE `Organizations` (
`id` varchar(50) NOT NULL,
`name` varchar(100) NOT NULL,
`taxPayerId` varchar(50) DEFAULT NULL,
`businessName` varchar(100) DEFAULT NULL,
`status` varchar(15) NOT NULL DEFAULT 'TESTING',
`createdAt` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updatedAt` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
`activatedAt` timestamp NULL DEFAULT NULL,
`assetConfiguration` json DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
When I run:
select * from VehicleTickets where organizationId not in (
select id from Organizations
);
I get an empty result set.
However, if I run a query like this:
insert into `VehicleTickets` (
`id`,
`createdAt`,
`organizationId`,
`ticketInfo`,
`vehiclePlate`
)
values (
'... application generated id',
'... current date ',
'cjlchoksi01r8nfks3f51kht8', -- DOES EXIST on Organizations
'{ ... some JSON payload }',
'... vehicle plate'
)
This produces the following error:
Cannot add or update a child row: a foreign key constraint fails
(VehicleTickets, CONSTRAINT VehicleTickets_Organizations_fk
FOREIGN KEY (organizationId) REFERENCES Organizations (id))
Additionally, it gives me:
"errno": 1452,
"sqlState": "23000",
I've read through several threads regarding this issue, but couldn't find a similar case.

MySQL Foreign Key format during table creation

I've run into a strange situation. I have two tables that initially looked like this:
CREATE TABLE vendors (
vendor_id INT UNSIGNED NOT NULL AUTO_INCREMENT,
[...]
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (vendor_id)
) ENGINE=InnoDB CHARACTER SET=utf8mb4;
CREATE TABLE vendor_orders (
vendor_order_id INT UNSIGNED NOT NULL AUTO_INCREMENT,
vendor_id INT UNSIGNED NOT NULL REFERENCES vendors(vendor_id),
[...]
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (vendor_order_id)
) ENGINE=InnoDB CHARACTER SET=utf8mb4;
However, after inspecting the database, I discovered the foreign key in the table definition for vendor_orders wasn't created. I then tried to create the second table like this:
CREATE TABLE vendor_orders (
vendor_order_id INT UNSIGNED NOT NULL AUTO_INCREMENT,
vendor_id INT UNSIGNED NOT NULL,
[...]
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (vendor_order_id),
FOREIGN KEY (vendor_id) REFERENCES vendors(vendor_id)
) ENGINE=InnoDB CHARACTER SET=utf8mb4;
That worked, and my foreign key was created. Can anyone tell me what the difference between the two formats is? I thought both were supposed to be equivalent. I'm using MySQL 5.6.33.
Your expectation was correct, the references keyword as you used in the first example should create the foreign key, but it does not work that way. You are not the first who ran into this MySQL bug. The solution is to avoid using the inline foreign key definition and explicitly write out the foreign key as you did in the second example.

Mysql Percona crushes the table while trying to create a unique index on fields where there is a generated one

CREATE TABLE tasks (
`user_id` INT(10) UNSIGNED NOT NULL,
`name` VARCHAR(255) NOT NULL,
`code` VARCHAR(255) NOT NULL,
`params` JSON,
`hash` VARCHAR(32) GENERATED ALWAYS AS (MD5(`params`)),
`created_at` TIMESTAMP NULL DEFAULT NULL,
`updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
CONSTRAINT `tasks_user_id_users_id_fk`
FOREIGN KEY (`user_id`) REFERENCES `users`(`id`)
)ENGINE=INNODB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
then i try to add a unique index on user_id and hash, i tried to do it during the table create, but there were a problem with the foreign key, so i decided to do it separately.
ALTER TABLE tasks
ADD UNIQUE INDEX `tasks_user_id_hash_unique_idx` (`user_id`, `hash`);
Then i get strange problem error 1146
Table '<dbname>.tasks' doesn't exist
Since then strange errors
1. I cannot delete it while it exists and i cannot do with it anything, cause it does not exist. After mysql reload I get the table deleted but if i try to create it again:
Error Code: 1813
Tablespace '<dbname>.tasks' exists.
I found the decision for unique field, i simply genereate md5( hash + user_id) UNIQUE. But How can I get rid of that problem which still exists and what is going on. It looks like a BUG in mysql Percona 5.7.14-7
so the right way to create the table
CREATE TABLE tasks (
`user_id` INT(10) UNSIGNED NOT NULL,
`name` VARCHAR(255) NOT NULL,
`code` VARCHAR(255) NOT NULL,
`params` JSON,
`hash` VARCHAR(32) GENERATED ALWAYS AS (MD5(CONCAT(`params`,`user_id`))) UNIQUE,
`created_at` TIMESTAMP NULL DEFAULT NULL,
`updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
CONSTRAINT `tasks_user_id_users_id_fk`
FOREIGN KEY (`user_id`) REFERENCES `users`(`id`)
)ENGINE=INNODB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
But, again, the question with the ghosts still exists after the first tries!

MySQL - delete rows rejected on INNODB table

I have two tables - a user table and a userlog table.
CREATE TABLE `client_user` (
`id_client_user` int(11) NOT NULL auto_increment,
`Nom` varchar(45) NOT NULL,
`Prenom` varchar(45) NOT NULL,
`email` varchar(255) NOT NULL,
`userid` varchar(45) NOT NULL,
`password` varchar(45) NOT NULL,
`active` tinyint(1) NOT NULL default '0',
`lastaccess` timestamp NULL default NULL,
`user_must_change_pwd` tinyint(1) NOT NULL default '0',
PRIMARY KEY (`id_client_user`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `user_log` (
`id_user_log` int(11) NOT NULL auto_increment,
`access` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP,
`zone_updated` varchar(255) NOT NULL,
`id_client_user` int(11) NOT NULL,
PRIMARY KEY (`id_user_log`),
KEY `fk_user_log_client_user1` (`id_client_user`),
CONSTRAINT `fk_user_log_client_user1`
FOREIGN KEY (`id_client_user`)
REFERENCES `client_user` (`id_client_user`)
ON DELETE NO ACTION
ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
I create a user in the client_user table and then his activity is logged within the user_log table.
I now need to delete rows in the user_log table.
This is rejected because of the foreign key constraint - that much I have understood.
After having looked at the documentation, I have not seen how I can change the foreign key to allow me to delete the user_log records.
What I need is a foreign key (1:n), client_user (1) to user_log (n), where user_log records can be deleted without impacting the associated client_user record.
I am sure that this is possible with innodb, but I cannot see how.
Help ?
From the specification
InnoDB supports the use of ALTER TABLE to drop foreign keys:
ALTER TABLE tbl_name DROP FOREIGN KEY fk_symbol;

mysql won't allow foreign key

Many people had this problem already, but there was no fitting solution in other posts.
I have two tables, one named "sales", the other named "host_flags". I would like to have a foreign key for host_flags.sales_id to sales.id, but mysql won't let me! I have primary indexes defined in each table, so I wonder why...
The host_flags table already has a foreign key on the column host_id, but even when I tried and created the foreign key for the sales id first, it wouldn't let me.
The tables look like:
CREATE TABLE `sales` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`email` varchar(255) DEFAULT NULL,
`password` varchar(255) DEFAULT NULL,
`creation` datetime DEFAULT NULL,
`lastupdate` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1;
CREATE TABLE `host_flags` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`host_id` int(11) DEFAULT NULL,
`sales_id` int(11) DEFAULT NULL,
`creation` datetime DEFAULT NULL,
`lastupdate` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `host_id6` (`host_id`),
CONSTRAINT `host_id6` FOREIGN KEY (`host_id`) REFERENCES `hosts` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CREATE TABLE `hosts` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`creation` datetime NOT NULL,
`lastupdate` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=32225 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
I get this error message:
MySQL said: Can't create table 'primarydata.#sql-191_1' (errno: 150)
Thanks!
Charles
SOLUTION FOUND
All ints of the primary indexes have to be either signed or unsigned - not mixed.
Typically:
I like to declare the FK constraints outside of the table definition after all tables have been constructed.
ALTER TABLE `tbl`
ADD CONSTRAINT `constr`
FOREIGN KEY `fk_id` REFERENCES `ftbl`(`id`)
ON UPDATE CASCADE
ON DELETE CASCADE;
This way I can make sure the problem isn't something like the datatype of tbl.fk_id not being the same as the one of ftbl.id (including UNSIGNED as #Devart said). Or not having declared ftbl.id as unique. Regardless of the order of declaration of the tables.
After i do this i can integrate the constraint back into the table definition and take into account the order in which the tables need to be created to allow the constraint to be added.
You problem:
-- creating the sales table
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
-- creating the host_flags table
`sales_id` int(11) DEFAULT NULL,
-- the sales.id is declared as unsigned
-- the host_flags.sales_id is declared signed
Additonally to Recursed's answer:
There is a requirement that foreign keys contstraints' names must be unique in database scope. Maybe changing the name will work?
There is also a huge thread on MySQL community forums about the problem containing several solutions for some specific situations.
Possible two errors:
Reference and referenced columns must have the same type - int(11) unsigned
Unknown referenced table hosts.