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

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;

Related

I am trying to add foreign key constraint and am unable to figure out why it isn't adding the constraint [duplicate]

I am creating 2 tables in my database:
DROP TABLE IF EXISTS `med_pharmacy`;
CREATE TABLE IF NOT EXISTS `med_pharmacy` (
`med_pharmacy_id` int(11) NOT NULL AUTO_INCREMENT,
`med_id` int(11) NOT NULL,
`med_barcode` varchar(45) DEFAULT NULL,
`med_received` date DEFAULT NULL,
`med_expiry` date DEFAULT NULL,
`med_tablet` int(11) DEFAULT NULL,
`med_pill` int(11) DEFAULT NULL,
`clinic_id` varchar(45) DEFAULT NULL,
PRIMARY KEY (`med_pharmacy_id`),
KEY `fk_med_pharmacy_medication1_idx` (`med_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1261 DEFAULT CHARSET=utf8mb4;
AND:
DROP TABLE IF EXISTS `medication`;
CREATE TABLE `medication` (
`med_id` int(11) NOT NULL,
`med_name` varchar(75) NOT NULL,
`med_date_added` date DEFAULT NULL,
`clinic_id` varchar(45) DEFAULT NULL,
`med_type` varchar(15) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
And when I run the queries in wamp I got this error:
SQL query:
ALTER TABLE `med_pharmacy`
ADD CONSTRAINT `fk_med_pharmacy_medication1`
FOREIGN KEY (`med_id`)
REFERENCES
`medication` (`med_id`) ON DELETE CASCADE ON UPDATE CASCADE MySQL
said: Documentation
#1822 - Failed to add the foreign key constaint. Missing index for constraint 'fk_med_pharmacy_medication1' in the referenced table
'medication'
The tables already exists but I changed one field.
The column referenced in a foreign key must be indexed. You need to add an index on medication.med_id. In fact, this should probably be the primary key of the table.
ALTER TABLE medication ADD PRIMARY KEY (med_id);
if you are giving
ADD CONSTRAINT `fk_med_pharmacy_medication1`
FOREIGN KEY (`med_id`)
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 med_id should have primary key in medication or reference the columns of a UNIQUE constraint

MySQL error: Missing index for constraint

I am creating 2 tables in my database:
DROP TABLE IF EXISTS `med_pharmacy`;
CREATE TABLE IF NOT EXISTS `med_pharmacy` (
`med_pharmacy_id` int(11) NOT NULL AUTO_INCREMENT,
`med_id` int(11) NOT NULL,
`med_barcode` varchar(45) DEFAULT NULL,
`med_received` date DEFAULT NULL,
`med_expiry` date DEFAULT NULL,
`med_tablet` int(11) DEFAULT NULL,
`med_pill` int(11) DEFAULT NULL,
`clinic_id` varchar(45) DEFAULT NULL,
PRIMARY KEY (`med_pharmacy_id`),
KEY `fk_med_pharmacy_medication1_idx` (`med_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1261 DEFAULT CHARSET=utf8mb4;
AND:
DROP TABLE IF EXISTS `medication`;
CREATE TABLE `medication` (
`med_id` int(11) NOT NULL,
`med_name` varchar(75) NOT NULL,
`med_date_added` date DEFAULT NULL,
`clinic_id` varchar(45) DEFAULT NULL,
`med_type` varchar(15) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
And when I run the queries in wamp I got this error:
SQL query:
ALTER TABLE `med_pharmacy`
ADD CONSTRAINT `fk_med_pharmacy_medication1`
FOREIGN KEY (`med_id`)
REFERENCES
`medication` (`med_id`) ON DELETE CASCADE ON UPDATE CASCADE MySQL
said: Documentation
#1822 - Failed to add the foreign key constaint. Missing index for constraint 'fk_med_pharmacy_medication1' in the referenced table
'medication'
The tables already exists but I changed one field.
The column referenced in a foreign key must be indexed. You need to add an index on medication.med_id. In fact, this should probably be the primary key of the table.
ALTER TABLE medication ADD PRIMARY KEY (med_id);
if you are giving
ADD CONSTRAINT `fk_med_pharmacy_medication1`
FOREIGN KEY (`med_id`)
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 med_id should have primary key in medication or reference the columns of a UNIQUE constraint

MySQL composite unique key and foreign key bug

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

Cannot add or update a child row: a foreign key constraint fails mysql

CREATE TABLE `class` (
`class_id` int(11) NOT NULL AUTO_INCREMENT,
`section_name` varchar(50) NOT NULL,
`class_alias` varchar(200) NOT NULL,
`grading_scheme` int(11) NOT NULL DEFAULT '0',
`year` year(4) NOT NULL,
`grade_calc_method_id` varchar(20) DEFAULT NULL,
PRIMARY KEY (`class_id`)
) ENGINE=InnoDB AUTO_INCREMENT=48819 DEFAULT CHARSET=latin1;
CREATE TABLE `teachers` (
`teacher_id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`teacher_subject` varchar(20) NOT NULL DEFAULT 'None',
PRIMARY KEY (`teacher_id`),
KEY `user_id` (`user_id`,`school_id`)
) ENGINE=InnoDB AUTO_INCREMENT=48606 DEFAULT CHARSET=latin1;
CREATE TABLE `teacher_classes` (
`teacher_class_id` int(11) NOT NULL AUTO_INCREMENT,
`teacher_id` int(11) NOT NULL,
`class_id` int(11) NOT NULL,
PRIMARY KEY (`teacher_class_id`),
UNIQUE KEY `teacher_id_class_id` (`teacher_id`,`class_id`),
KEY `teacher_id` (`teacher_id`,`class_id`)
) ENGINE=InnoDB AUTO_INCREMENT=46707 DEFAULT CHARSET=latin1;
Trying to insure data consistency between the tables by using foreign key so that the DBMS can check for errors.I have another junction table teacher_classes
Here is my query to add foreign keys constraint
ALTER TABLE teacher_classes
ADD CONSTRAINT `tc_fk_class_id` FOREIGN KEY (`class_id`)
REFERENCES class (`class_id`) ON UPDATE NO ACTION ON DELETE NO ACTION,
ADD CONSTRAINT `tc_fk_teacher_id` FOREIGN KEY (`teacher_id`)
REFERENCES teachers (`teacher_id`) ON UPDATE NO ACTION ON DELETE NO ACTION;
've seen the other posts on this topic, but no luck, getting following error.
Cannot add or update a child row: a foreign key constraint fails
(DB_NAME.#sql-403_12, CONSTRAINT
tc_fk_teacher_id FOREIGN KEY (teacher_id) REFERENCES teachers
(teacher_id) ON DELETE NO ACTION ON UPDATE NO ACTION)
Too late to Answer. I just had the same problem the solution is easy.
You're getting this error because you're trying to or UPDATE a row to teacher_classes doesn't match the id in table teachers.
A simple solution is disable foreign key checks before performing any operation on the table.
SET FOREIGN_KEY_CHECKS = 0;
After you are done with the table enable it again.
SET FOREIGN_KEY_CHECKS = 1;
Or you can remove not null constraint and insert a NULL value in it.
That's most probably the column definition doesn't match properly. For table teachers the PK column definition is as below.
`teacher_id` int(11) NOT NULL AUTO_INCREMENT
Make sure you have the same definition in your child table teacher_classes

Foreign Key not working: Error code 1005, SQL state HY000: Can't create table

I have two tables I have created and I'm adding the foreign key constraint after the fact.
The two tables are defined as such:
CREATE TABLE `user` (
`user_id` int(11) NOT NULL auto_increment,
`user_ad_id` varchar(500) default NULL,
`user_name` varchar(100) NOT NULL,
`login_id` varchar(100) default NULL,
`email` varchar(256) NOT NULL,
`personal_config` int(10) NOT NULL,
PRIMARY KEY (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
and
CREATE TABLE IF NOT EXISTS personal_config (
config_id INT(10) NOT NULL AUTO_INCREMENT,
last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
configuration TEXT(25600) NOT NULL,
PRIMARY KEY (config_id)
)ENGINE=InnoDB DEFAULT CHARSET=utf8;
ALTER TABLE personal_config ADD CONSTRAINT personal_config_fk_user FOREIGN KEY
(config_id) REFERENCES user(personal_config);
And I keep getting the same error but can't figure it out. I've searched all the related threads to this.
Your FK config_id can't be an autoincrement field, that doesn't make much sense right? That field reflects a value in the foreign table, it cannot be set arbitrarily in the local table.
I think this is what you want:
ALTER TABLE user ADD CONSTRAINT personal_config_fk_user FOREIGN KEY (personal_config) REFERENCES personal_config(config_id);
Your ALTER TABLE statement is backward. Since personal_config.config_id is an auto_increment primary key, the foreign key should be defined in the users table against personal_config, not in personal_config against the users table.
ALTER TABLE users ADD CONSTRAINT user_fk_personal_config
FOREIGN KEY (personal_config)
REFERENCES personal_config(config_id);
if you set your user table field personal_config is primary key then it is possible to execute
CREATE TABLE IF NOT EXISTS personal_config (
config_id INT(10) NOT NULL AUTO_INCREMENT,
last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
configuration TEXT(25600) NOT NULL,
PRIMARY KEY (config_id), FOREIGN KEY
(config_id) REFERENCES user(personal_config)
)ENGINE=InnoDB DEFAULT CHARSET=utf8;