MySQL composite unique key and foreign key bug - mysql

It seems that adding composite unique key with foreign keys included breaks the table: unable to drop unique key:
drop index test_unq on order_test
Error:
Cannot drop index 'test_unq': needed in a foreign key constraint
Steps to reproduce:
create table product_test (
id bigint unsigned not null auto_increment primary key
);
create table order_test (
id bigint unsigned not null auto_increment primary key,
product_id bigint unsigned not null,
foreign key (product_id) references product_test(id)
);
alter table order_test add some_field int not null;
alter table order_test add unique test_unq(product_id, some_field);
Running
SHOW CREATE TABLE order_test
returns
CREATE TABLE `order_test` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`product_id` bigint(20) unsigned NOT NULL,
`some_field` int(11) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `test_unq` (`product_id`,`some_field`),
CONSTRAINT `order_test_ibfk_1` FOREIGN KEY (`product_id`) REFERENCES
`product_test` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
Result looks invalid, there is a constraint but no key for product_id.
Any ideas how to recover table without dropping and creating it again?
Thanks!
EDIT:
Removing all other foreign keys does not help! Structure after removing:
CREATE TABLE `order_test` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`product_id` bigint(20) unsigned NOT NULL,
`some_field` int(11) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `test_unq` (`product_id`,`some_field`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
Same error when I try to drop index.
drop index test_unq on order_test
Error:
Cannot drop index 'test_unq': needed in a foreign key constraint

Related

mysql 8 (innodb) foreign key constraints on newly created indexes

Suppose I have a table items
with columns id (PRIMARY), name(VARCHAR), section_id (BIGINT), updated_at (DATETIME),
and a table sections with id (PRIMARY).
Naturally, items.section_id is a foreign key that refers to sections.id.
Suppose there is an index on items of the columns (section_id, name). I believe that if you tried to drop this index, you would get an error that it is needed in a foreign key constraint. I can accept this.
Now, I want to create a new index, like create index ix_section_id_id_updated_at on items (section_id, id, updated_at). MySQL lets me do this, but if I go to drop this table, I get that same error: it fails, because it is needed in a foreign key constraint.
Why should this be? It already has one index that can be used for this foreign key check. Further, the error does NOT go away with set FOREIGN_KEY_CHECKS=0;. Is there a way to force MySQL to not associate the new index with the foreign key, so that it is quick to drop? This is necessary because I will be running the migration on a production server with temporary downtime, and need to be able to quickly revert the migration in case of anything going wrong afterwards.
I can reproduce your issue if I don't create an index on section_id and allow mysql to do so on the creation of a foreign key(as described in the manual). Adding a new index drops the auto generated key and if you then drop the new index an error is generated because of the requirement to have a key , and mysql does not auto generate one on a drop.. . If you manually generate a key on section_id this problem does not happen..and the newly created compound index drops successfully.
drop table if exists items;
drop table if exists sections;
create table items(id int PRIMARY key, name varchar(3), section_id BIGINT, updated_at DATETIME);
create table sections(id bigint primary key);
alter table items
add foreign key fk1(section_id) references sections(id);
show create table items;
CREATE TABLE `items` ( `id` int(11) NOT NULL,
`name` varchar(3) DEFAULT NULL,
`section_id` bigint(20) DEFAULT NULL,
`updated_at` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `fk1` (`section_id`),
CONSTRAINT `fk1` FOREIGN KEY (`section_id`) REFERENCES `sections` (`id`)) ENGINE=InnoDB DEFAULT CHARSET=latin1;
alter table items
add key key1(section_id, name);
show create table items;
CREATE TABLE `items` (
`id` int(11) NOT NULL,
`name` varchar(3) DEFAULT NULL,
`section_id` bigint(20) DEFAULT NULL,
`updated_at` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `key1` (`section_id`,`name`),
CONSTRAINT `fk1` FOREIGN KEY (`section_id`) REFERENCES `sections` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
and with manually generated key
drop table if exists items;
drop table if exists sections;
create table items(id int PRIMARY key, name varchar(3), section_id BIGINT, updated_at DATETIME);
create table sections(id bigint primary key);
alter table items
add key sid(section_id);
alter table items
add foreign key fk1(section_id) references sections(id);
show create table items;
CREATE TABLE `items` (
`id` int(11) NOT NULL,
`name` varchar(3) DEFAULT NULL,
`section_id` bigint(20) DEFAULT NULL,
`updated_at` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `sid` (`section_id`),
CONSTRAINT `fk1` FOREIGN KEY (`section_id`) REFERENCES `sections` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
alter table items
add key key1(section_id, name);
show create table items;
CREATE TABLE `items` (
`id` int(11) NOT NULL,
`name` varchar(3) DEFAULT NULL,
`section_id` bigint(20) DEFAULT NULL,
`updated_at` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `sid` (`section_id`),
KEY `key1` (`section_id`,`name`),
CONSTRAINT `fk1` FOREIGN KEY (`section_id`) REFERENCES `sections` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

Can't add foreign key in MySQL Database

Trying to create a simple relation between two fields in two tables - 'Task' table with the field 'USER_TOKEN' and the 'USER' table with the field 'TOKEN'. The two fields are the same structure. As you can see the error and other things that may assist you to help me understand the problem and fix it.
System: MacOS 10.12.3 | DB : MySQL 5.7.17 | DBM : Sequel Pro
Error : MySQL said: Cannot add foreign key constraint
CREATE TABLE `TASK` (
`ID` int(11) unsigned NOT NULL AUTO_INCREMENT,
`USER_TOKEN` int(11) unsigned NOT NULL,
PRIMARY KEY (`ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `USER` (
`ID` int(11) unsigned NOT NULL AUTO_INCREMENT,
`TOKEN` int(11) unsigned NOT NULL,
PRIMARY KEY (`ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
ALTER TABLE USER
ADD CONSTRAINT TOKENS
FOREIGN KEY (`TOKEN`) REFERENCES `category`(`USER_TOKEN`)
Thanks.
If you really want to create a foreign key to a non-primary key, it MUST be a column that has a unique constraint on it.
A FOREIGN KEY constraint does not have to be linked only to a PRIMARY KEY constraint in another table; it can also be defined to reference the columns of a UNIQUE constraint in another table.
So your USER_TOKEN column of table TASK and TOKEN column of USER table must be UNIQUE. So run the following query:
CREATE TABLE `TASK` (
`ID` int(11) unsigned NOT NULL AUTO_INCREMENT,
`USER_TOKEN` int(11) unsigned NOT NULL UNIQUE,
PRIMARY KEY (`ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `USER` (
`ID` int(11) unsigned NOT NULL AUTO_INCREMENT,
`TOKEN` int(11) unsigned NOT NULL UNIQUE,
PRIMARY KEY (`ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
ALTER TABLE `USER`
ADD CONSTRAINT `TOKENS`
FOREIGN KEY (`TOKEN`) REFERENCES `TASK`(`USER_TOKEN`);
Check Demo here

Change Primary Key from BigInt to Unsigned BigInt when linked as foreign key

I have a scenario like this:
CREATE TABLE `Users` (
`IdUser` bigint(20) NOT NULL PRIMARY KEY
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `MainTable` (
`IdLite` bigint(20) NOT NULL PRIMARY KEY
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `LinkedTable` (
`IdUser` bigint(20) NOT NULL,
`IdLite` bigint(20) NOT NULL,
PRIMARY KEY (`IdUser`, `IdLite`),
FOREIGN KEY (`IdUser`) REFERENCES `Users` (`IdUser`),
FOREIGN KEY (`IdLite`) REFERENCES `MainTable` (`IdLite`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
I'm trying to change IdLite to Unsigned with a query like this:
SET FOREIGN_KEY_CHECKS=0;
ALTER TABLE `MainTable` CHANGE `IdLite`
`IdLite` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT;
ALTER TABLE `LinkedTable` CHANGE `IdLite`
`IdLite` BIGINT(20) UNSIGNED NOT NULL;
SET FOREIGN_KEY_CHECKS=1;
but I get error:
errno: 150 - Foreign key constraint is incorrectly formed
How can I solve?
You can't change the data type of columns used in an existing FK constraint.
You can drop the FK constraint, change the column data types and then recreate the FK constraint:
ALTER TABLE LinkedTable
DROP FOREIGN KEY linkedtable_ibfk_2; -- or whatever the symbol is named
ALTER TABLE MainTable
MODIFY IdLite SERIAL; -- alias of BIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE
ALTER TABLE LinkedTable
MODIFY IdLite BIGINT UNSIGNED NOT NULL,
ADD FOREIGN KEY (IdLite) REFERENCES MainTable (IdLite);

whether it is possible to use a foreign key to the table enum?

whether it is possible to use a foreign key to the table enum?
CREATE TABLE wiele (
id_wiele INT(11) NOT NULL AUTO_INCREMENT,
nazwa_wiele CHAR(50) NOT NULL DEFAULT '0',
PRIMARY KEY (id_wiele),
UNIQUE INDEX id (id_wiele)
)
COLLATE='latin1_swedish_ci'
ENGINE=InnoDB
AUTO_INCREMENT=4;
CREATE TABLE `gotowe` (
`id` INT(11) NOT NULL,
`parametr` ENUM('Y','N','D') NOT NULL,
`parametry` SET('A','B','C') NOT NULL,`enter code here`
PRIMARY KEY (`id`),
UNIQUE INDEX `id` (`id`)
)
COLLATE='latin1_swedish_ci'
ENGINE=InnoDB;
Foreign Key Mismatch Error :] .

Mysql FOREIGN KEY error 150

CREATE TABLE IF NOT EXISTS `questions` (
`question_id` int(11) NOT NULL AUTO_INCREMENT,
`createddate` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updateddate` timestamp NULL DEFAULT NULL,
`active_flag` tinyint(4) NOT NULL DEFAULT '0',
PRIMARY KEY (`question_id`),
UNIQUE KEY `id_UNIQUE` (`question_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
CREATE TABLE `alarts` (
`alart_id` BIGINT(20) unsigned NOT NULL AUTO_INCREMENT,
`alart_name` varchar(45) NOT NULL,
`interval` int(10) unsigned NOT NULL,
`alart_sent_counter` int(10) unsigned NOT NULL,
`alart_types_id` BIGINT(20) unsigned NOT NULL,
`contact_group_id` int(10) unsigned NOT NULL,
PRIMARY KEY (`alart_id`),
FOREIGN KEY (`alart_types_id`) REFERENCES alart_types(`alart_types_id`)
) ENGINE=InnoDB AUTO_INCREMENT=20 DEFAULT CHARSET=utf8;
I want to create new table with two FOREIGN KEY like this:
CREATE TABLE `alart_question_mapping` (
`alart_question_mapping_id` BIGINT(20) unsigned NOT NULL AUTO_INCREMENT,
`question_id` int(11) NOT NULL,
`alart_id` BIGINT(20) unsigned NOT NULL,
PRIMARY KEY (`alart_question_mapping_id`),
FOREIGN KEY (`question_id`) REFERENCES questions(`question_id`),
FOREIGN KEY (`alart_id`) REFERENCES alart_types(`alart_id`)
) ENGINE=InnoDB AUTO_INCREMENT=20 DEFAULT CHARSET=utf8;
but I am getting error:
Error Code: 1005. Can't create table 'alart_question_mapping' (errno: 150)
How can I create this table ?
Thank's.
Chane the statement:
FOREIGN KEY (`alart_id`) REFERENCES alart_types(`alart_id`)
to
FOREIGN KEY (`alart_id`) REFERENCES alarts(`alart_id`)
The only thing I can see is you are referencing a table in your CREATE TABLE statement that is not present in what you provided:
FOREIGN KEY (`alart_id`) REFERENCES alart_types(`alart_id`)
If you remove this reference the table will create. See SQL Fiddle with Demo
Edit #1, based on your update the problem is you are referencing the wrong field in your last table:
Change this:
CREATE TABLE `alart_question_mapping` (
`alart_question_mapping_id` BIGINT(20) unsigned NOT NULL AUTO_INCREMENT,
`question_id` int(11) NOT NULL,
`alart_id` BIGINT(20) unsigned NOT NULL,
PRIMARY KEY (`alart_question_mapping_id`),
FOREIGN KEY (`question_id`) REFERENCES questions(`question_id`),
FOREIGN KEY (`alart_id`) REFERENCES alart_types(`alart_id`)
)
To this:
CREATE TABLE `alart_question_mapping` (
`alart_question_mapping_id` BIGINT(20) unsigned NOT NULL AUTO_INCREMENT,
`question_id` int(11) NOT NULL,
`alart_id` BIGINT(20) unsigned NOT NULL,
PRIMARY KEY (`alart_question_mapping_id`),
FOREIGN KEY (`question_id`) REFERENCES questions(`question_id`),
FOREIGN KEY (`alart_id`) REFERENCES alart_types(`alart_types_id`)
) ENGINE=InnoDB AUTO_INCREMENT=20 DEFAULT CHARSET=utf8;
So you are changing this line:
FOREIGN KEY (`alart_id`) REFERENCES alart_types(`alart_id`)
to this:
FOREIGN KEY (`alart_id`) REFERENCES alart_types(`alart_types_id`)
If you are referencing the alart_types table then you will want to reference the alart_types_id not the alart_id
see SQL Fiddle with Demo
It can't find table alart_types.
From MySQL Foreign Key Constraints
If you re-create a table that was dropped, it must have a definition
that conforms to the foreign key constraints referencing it. It must
have the right column names and types, and it must have indexes on the
referenced keys, as stated earlier. If these are not satisfied, MySQL
returns error number 1005 and refers to error 150 in the error
message.
I think you mean
FOREIGN KEY (`alart_id`) REFERENCES alart(`alart_id`)
instead of
FOREIGN KEY (`alart_id`) REFERENCES alart_types(`alart_id`)
Hope this makes sense.
In this table
CREATE TABLE alart_types (
alart_types_id BIGINT(20) unsigned NOT NULL AUTO_INCREMENT,
alarts_types_name varchar(45) NOT NULL,
PRIMARY KEY (alart_types_id)
) ENGINE=InnoDB AUTO_INCREMENT=20 DEFAULT CHARSET=utf8;
it doesn't really make sense to have an autoincrement id number without also having a unique constraint on alarts_types_name. Without that unique constraint, you're almost certain to end up with a table whose data looks like this.
1 Warning
2 Critical
3 Warning
4 Warning
This constraint references a column that doesn't exist.
FOREIGN KEY (`alart_id`) REFERENCES alart_types(`alart_id`)
It should be
FOREIGN KEY (`alart_id`) REFERENCES alart_types(`alart_types_id`)