Cannot change column used in a foreign key constraint - mysql

I got this error when i was trying to alter my table.
Error Code: 1833. Cannot change column 'person_id': used in a foreign key constraint 'fk_fav_food_person_id' of table 'table.favorite_food'
Here is my CREATE TABLE STATEMENT Which ran successfully.
CREATE TABLE favorite_food(
person_id SMALLINT UNSIGNED,
food VARCHAR(20),
CONSTRAINT pk_favorite_food PRIMARY KEY(person_id,food),
CONSTRAINT fk_fav_food_person_id FOREIGN KEY (person_id)
REFERENCES person (person_id)
);
Then i tried to execute this statement and i got the above error.
ALTER TABLE person MODIFY person_id SMALLINT UNSIGNED AUTO_INCREMENT;

You can turn off foreign key checks:
SET FOREIGN_KEY_CHECKS = 0;
/* DO WHAT YOU NEED HERE */
SET FOREIGN_KEY_CHECKS = 1;
Please make sure to NOT use this on production and have a backup.

The type and definition of foreign key field and reference must be equal.
This means your foreign key disallows changing the type of your field.
One solution would be this:
LOCK TABLES
favorite_food WRITE,
person WRITE;
ALTER TABLE favorite_food
DROP FOREIGN KEY fk_fav_food_person_id,
MODIFY person_id SMALLINT UNSIGNED;
Now you can change you person_id
ALTER TABLE person MODIFY person_id SMALLINT UNSIGNED AUTO_INCREMENT;
recreate foreign key
ALTER TABLE favorite_food
ADD CONSTRAINT fk_fav_food_person_id FOREIGN KEY (person_id)
REFERENCES person (person_id);
UNLOCK TABLES;
EDIT:
Added locks above, thanks to comments
You have to disallow writing to the database while you do this,
otherwise you risk data integrity problems.
I've added a write lock above
All writing queries in any other session than your own ( INSERT, UPDATE, DELETE ) will wait till timeout or UNLOCK TABLES; is executed
http://dev.mysql.com/doc/refman/5.5/en/lock-tables.html
EDIT 2: OP asked for a more detailed explanation of the line "The type and definition of foreign key field and reference must be equal. This means your foreign key disallows changing the type of your field."
From MySQL 5.5 Reference Manual: FOREIGN KEY Constraints
Corresponding columns in the foreign key and the referenced key must
have similar internal data types inside InnoDB so that they can be
compared without a type conversion. The size and sign of integer types
must be the same. The length of string types need not be the same. For
nonbinary (character) string columns, the character set and collation
must be the same.

In my case it was necessary to add GLOBAL.
SET FOREIGN_KEY_CHECKS = 0;
SET GLOBAL FOREIGN_KEY_CHECKS=0;
/* DO WHAT YOU NEED HERE */
SET FOREIGN_KEY_CHECKS = 1;
SET GLOBAL FOREIGN_KEY_CHECKS=1;

Go to the structure tab of the table in question.
Under actions you have indexes.
Drop them
Once you are finished with the necessary modifications,
Bring back the foreign key and restore the indexes deleted. Then make sure your structure is the same and has not changed

When you set keys (primary or foreign) you are setting constraints on how they can be used, which in turn limits what you can do with them. If you really want to alter the column, you could re-create the table without the constraints, although I'd recommend against it. Generally speaking, if you have a situation in which you want to do something, but it is blocked by a constraint, it's best resolved by changing what you want to do rather than the constraint.

Related

MySQL cannot add foreign key #1215 - Cannot add foreign key constraint [duplicate]

I am trying to create a table in MySQL with two foreign keys, which reference the primary keys in 2 other tables, but I am getting an errno: 150 error and it will not create the table.
Here is the SQL for all 3 tables:
CREATE TABLE role_groups (
`role_group_id` int(11) NOT NULL `AUTO_INCREMENT`,
`name` varchar(20),
`description` varchar(200),
PRIMARY KEY (`role_group_id`)
) ENGINE=InnoDB;
CREATE TABLE IF NOT EXISTS `roles` (
`role_id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(50),
`description` varchar(200),
PRIMARY KEY (`role_id`)
) ENGINE=InnoDB;
create table role_map (
`role_map_id` int not null `auto_increment`,
`role_id` int not null,
`role_group_id` int not null,
primary key(`role_map_id`),
foreign key(`role_id`) references roles(`role_id`),
foreign key(`role_group_id`) references role_groups(`role_group_id`)
) engine=InnoDB;
These conditions must be satisfied to not get error 150 re ALTER TABLE ADD FOREIGN KEY:
The Parent table must exist before you define a foreign key to reference it. You must define the tables in the right order: Parent table first, then the Child table. If both tables references each other, you must create one table without FK constraints, then create the second table, then add the FK constraint to the first table with ALTER TABLE.
The two tables must both support foreign key constraints, i.e. ENGINE=InnoDB. Other storage engines silently ignore foreign key definitions, so they return no error or warning, but the FK constraint is not saved.
The referenced columns in the Parent table must be the left-most columns of a key. Best if the key in the Parent is PRIMARY KEY or UNIQUE KEY.
The FK definition must reference the PK column(s) in the same order as the PK definition. For example, if the FK REFERENCES Parent(a,b,c) then the Parent's PK must not be defined on columns in order (a,c,b).
The PK column(s) in the Parent table must be the same data type as the FK column(s) in the Child table. For example, if a PK column in the Parent table is UNSIGNED, be sure to define UNSIGNED for the corresponding column in the Child table field.
Exception: length of strings may be different. For example, VARCHAR(10) can reference VARCHAR(20) or vice versa.
Any string-type FK column(s) must have the same character set and collation as the corresponding PK column(s).
If there is data already in the Child table, every value in the FK column(s) must match a value in the Parent table PK column(s). Check this with a query like:
SELECT COUNT(*) FROM Child LEFT OUTER JOIN Parent ON Child.FK = Parent.PK
WHERE Parent.PK IS NULL;
This must return zero (0) unmatched values. Obviously, this query is an generic example; you must substitute your table names and column names.
Neither the Parent table nor the Child table can be a TEMPORARY table.
Neither the Parent table nor the Child table can be a PARTITIONED table.
If you declare a FK with the ON DELETE SET NULL option, then the FK column(s) must be nullable.
If you declare a constraint name for a foreign key, the constraint name must be unique in the whole schema, not only in the table in which the constraint is defined. Two tables may not have their own constraint with the same name.
If there are any other FK's in other tables pointing at the same field you are attempting to create the new FK for, and they are malformed (i.e. different collation), they will need to be made consistent first. This may be a result of past changes where SET FOREIGN_KEY_CHECKS = 0; was utilized with an inconsistent relationship defined by mistake. See #andrewdotn's answer below for instructions on how to identify these problem FK's.
MySQL’s generic “errno 150” message “means that a foreign key constraint was not correctly formed.” As you probably already know if you are reading this page, the generic “errno: 150” error message is really unhelpful. However:
You can get the actual error message by running SHOW ENGINE INNODB STATUS; and then looking for LATEST FOREIGN KEY ERROR in the output.
For example, this attempt to create a foreign key constraint:
CREATE TABLE t1
(id INTEGER);
CREATE TABLE t2
(t1_id INTEGER,
CONSTRAINT FOREIGN KEY (t1_id) REFERENCES t1 (id));
fails with the error Can't create table 'test.t2' (errno: 150). That doesn’t tell anyone anything useful other than that it’s a foreign key problem. But run SHOW ENGINE INNODB STATUS; and it will say:
------------------------
LATEST FOREIGN KEY ERROR
------------------------
130811 23:36:38 Error in foreign key constraint of table test/t2:
FOREIGN KEY (t1_id) REFERENCES t1 (id)):
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.
It says that the problem is it can’t find an index. SHOW INDEX FROM t1 shows that there aren’t any indexes at all for table t1. Fix that by, say, defining a primary key on t1, and the foreign key constraint will be created successfully.
Make sure that the properties of the two fields you are trying to link with a constraint are exactly the same.
Often, the 'unsigned' property on an ID column will catch you out.
ALTER TABLE `dbname`.`tablename` CHANGE `fieldname` `fieldname` int(10) UNSIGNED NULL;
What's the current state of your database when you run this script? Is it completely empty? Your SQL runs fine for me when creating a database from scratch, but errno 150 usually has to do with dropping & recreating tables that are part of a foreign key. I'm getting the feeling you're not working with a 100% fresh and new database.
If you're erroring out when "source"-ing your SQL file, you should be able to run the command "SHOW ENGINE INNODB STATUS" from the MySQL prompt immediately after the "source" command to see more detailed error info.
You may want to check out the manual entry too:
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. If MySQL reports an error number 1005 from a CREATE TABLE statement, and the error message refers to error 150, table creation failed because a foreign key constraint was not correctly formed.
— MySQL 5.1 reference manual.
For people who are viewing this thread with the same problem:
There are a lot of reasons for getting errors like this. For a fairly complete list of causes and solutions of foreign key errors in MySQL (including those discussed here), check out this link:
MySQL Foreign Key Errors and Errno 150
For others that find this SO entry via Google: Be sure that you aren't trying to do a SET NULL action on a foreign key (to be) column defined as "NOT NULL." That caused great frustration until I remembered to do a CHECK ENGINE INNODB STATUS.
Definitely it is not the case but I found this mistake pretty common and unobvious. The target of a FOREIGN KEY could be not PRIMARY KEY. Te answer which become useful for me is:
A FOREIGN KEY always must be pointed to a PRIMARY KEY true field of other table.
CREATE TABLE users(
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(40));
CREATE TABLE userroles(
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT NOT NULL,
FOREIGN KEY(user_id) REFERENCES users(id));
As pointed by #andrewdotn the best way is to see the detailed error(SHOW ENGINE INNODB STATUS;) instead of just an error code.
One of the reasons could be that an index already exists with the same name, may be in another table. As a practice, I recommend prefixing table name before the index name to avoid such collisions. e.g. instead of idx_userId use idx_userActionMapping_userId.
Please make sure at first that
you are using InnoDB tables.
field for FOREIGN KEY has the same type and length (!) as source field.
I had the same trouble and I've fixed it. I had unsigned INT for one field and just integer for other field.
Helpful tip, use SHOW WARNINGS; after trying your CREATE query and you will receive the error as well as the more detailed warning:
---------------------------------------------------------------------------------------------------------+
| Level | Code | Message |
+---------+------+-------------------------------------------------------------------------- -------------------------------------------------------------------------------------------- ---------------+
| Warning | 150 | Create table 'fakeDatabase/exampleTable' with foreign key constraint failed. There is no index in the referenced table where the referenced columns appear as the first columns.
|
| Error | 1005 | Can't create table 'exampleTable' (errno:150) |
+---------+------+-------------------------------------------------------------------------- -------------------------------------------------------------------------------------------- ---------------+
So in this case, time to re-create my table!
This is usually happening when you try to source file into existing database.
Drop all the tables first (or the DB itself).
And then source file with SET foreign_key_checks = 0; at the beginning and SET foreign_key_checks = 1; at the end.
I've found another reason this fails... case sensitive table names.
For this table definition
CREATE TABLE user (
userId int PRIMARY KEY AUTO_INCREMENT,
username varchar(30) NOT NULL
) ENGINE=InnoDB;
This table definition works
CREATE TABLE product (
id int PRIMARY KEY AUTO_INCREMENT,
userId int,
FOREIGN KEY fkProductUser1(userId) REFERENCES **u**ser(userId)
) ENGINE=InnoDB;
whereas this one fails
CREATE TABLE product (
id int PRIMARY KEY AUTO_INCREMENT,
userId int,
FOREIGN KEY fkProductUser1(userId) REFERENCES User(userId)
) ENGINE=InnoDB;
The fact that it worked on Windows and failed on Unix took me a couple of hours to figure out. Hope that helps someone else.
MySQL Workbench 6.3 for Mac OS.
Problem: errno 150 on table X when trying to do Forward Engineering on a DB diagram, 20 out of 21 succeeded, 1 failed. If FKs on table X were deleted, the error moved to a different table that wasn't failing before.
Changed all tables engine to myISAM and it worked just fine.
Also worth checking that you aren't accidentally operating on the wrong database. This error will occur if the foreign table does not exist. Why does MySQL have to be so cryptic?
Make sure that the foreign keys are not listed as unique in the parent. I had this same problem and I solved it by demarcating it as not unique.
In my case it was due to the fact that the field that was a foreign key field had a too long name, ie. foreign key (some_other_table_with_long_name_id). Try sth shorter. Error message is a bit misleading in that case.
Also, as #Jon mentioned earlier - field definitions have to be the same (watch out for unsigned subtype).
(Side notes too big for a Comment)
There is no need for an AUTO_INCREMENT id in a mapping table; get rid of it.
Change the PRIMARY KEY to (role_id, role_group_id) (in either order). This will make accesses faster.
Since you probably want to map both directions, also add an INDEX with those two columns in the opposite order. (There is no need to make it UNIQUE.)
More tips: http://mysql.rjweb.org/doc.php/index_cookbook_mysql#speeding_up_wp_postmeta
When the foreign key constraint is based on varchar type, then in addition to the list provided by marv-el the target column must have an unique constraint.
execute below line before creating table :
SET FOREIGN_KEY_CHECKS = 0;
FOREIGN_KEY_CHECKS option specifies whether or not to check foreign key constraints for InnoDB tables.
-- Specify to check foreign key constraints (this is the default)
SET FOREIGN_KEY_CHECKS = 1;
 
-- Do not check foreign key constraints
SET FOREIGN_KEY_CHECKS = 0;
When to Use :
Temporarily disabling referential constraints (set FOREIGN_KEY_CHECKS to 0) is useful when you need to re-create the tables and load data in any parent-child order
I encountered the same problem, but I check find that I hadn't the parent table. So I just edit the parent migration in front of the child migration. Just do it.

How to add options unsigned on ID column after creating table and added foreign_key? [duplicate]

I got this error when i was trying to alter my table.
Error Code: 1833. Cannot change column 'person_id': used in a foreign key constraint 'fk_fav_food_person_id' of table 'table.favorite_food'
Here is my CREATE TABLE STATEMENT Which ran successfully.
CREATE TABLE favorite_food(
person_id SMALLINT UNSIGNED,
food VARCHAR(20),
CONSTRAINT pk_favorite_food PRIMARY KEY(person_id,food),
CONSTRAINT fk_fav_food_person_id FOREIGN KEY (person_id)
REFERENCES person (person_id)
);
Then i tried to execute this statement and i got the above error.
ALTER TABLE person MODIFY person_id SMALLINT UNSIGNED AUTO_INCREMENT;
You can turn off foreign key checks:
SET FOREIGN_KEY_CHECKS = 0;
/* DO WHAT YOU NEED HERE */
SET FOREIGN_KEY_CHECKS = 1;
Please make sure to NOT use this on production and have a backup.
The type and definition of foreign key field and reference must be equal.
This means your foreign key disallows changing the type of your field.
One solution would be this:
LOCK TABLES
favorite_food WRITE,
person WRITE;
ALTER TABLE favorite_food
DROP FOREIGN KEY fk_fav_food_person_id,
MODIFY person_id SMALLINT UNSIGNED;
Now you can change you person_id
ALTER TABLE person MODIFY person_id SMALLINT UNSIGNED AUTO_INCREMENT;
recreate foreign key
ALTER TABLE favorite_food
ADD CONSTRAINT fk_fav_food_person_id FOREIGN KEY (person_id)
REFERENCES person (person_id);
UNLOCK TABLES;
EDIT:
Added locks above, thanks to comments
You have to disallow writing to the database while you do this,
otherwise you risk data integrity problems.
I've added a write lock above
All writing queries in any other session than your own ( INSERT, UPDATE, DELETE ) will wait till timeout or UNLOCK TABLES; is executed
http://dev.mysql.com/doc/refman/5.5/en/lock-tables.html
EDIT 2: OP asked for a more detailed explanation of the line "The type and definition of foreign key field and reference must be equal. This means your foreign key disallows changing the type of your field."
From MySQL 5.5 Reference Manual: FOREIGN KEY Constraints
Corresponding columns in the foreign key and the referenced key must
have similar internal data types inside InnoDB so that they can be
compared without a type conversion. The size and sign of integer types
must be the same. The length of string types need not be the same. For
nonbinary (character) string columns, the character set and collation
must be the same.
In my case it was necessary to add GLOBAL.
SET FOREIGN_KEY_CHECKS = 0;
SET GLOBAL FOREIGN_KEY_CHECKS=0;
/* DO WHAT YOU NEED HERE */
SET FOREIGN_KEY_CHECKS = 1;
SET GLOBAL FOREIGN_KEY_CHECKS=1;
Go to the structure tab of the table in question.
Under actions you have indexes.
Drop them
Once you are finished with the necessary modifications,
Bring back the foreign key and restore the indexes deleted. Then make sure your structure is the same and has not changed
When you set keys (primary or foreign) you are setting constraints on how they can be used, which in turn limits what you can do with them. If you really want to alter the column, you could re-create the table without the constraints, although I'd recommend against it. Generally speaking, if you have a situation in which you want to do something, but it is blocked by a constraint, it's best resolved by changing what you want to do rather than the constraint.

Setting up foreign keys resulted to (errno:150 "Foreign key constraint incorrectly formed") [duplicate]

I am trying to create a table in MySQL with two foreign keys, which reference the primary keys in 2 other tables, but I am getting an errno: 150 error and it will not create the table.
Here is the SQL for all 3 tables:
CREATE TABLE role_groups (
`role_group_id` int(11) NOT NULL `AUTO_INCREMENT`,
`name` varchar(20),
`description` varchar(200),
PRIMARY KEY (`role_group_id`)
) ENGINE=InnoDB;
CREATE TABLE IF NOT EXISTS `roles` (
`role_id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(50),
`description` varchar(200),
PRIMARY KEY (`role_id`)
) ENGINE=InnoDB;
create table role_map (
`role_map_id` int not null `auto_increment`,
`role_id` int not null,
`role_group_id` int not null,
primary key(`role_map_id`),
foreign key(`role_id`) references roles(`role_id`),
foreign key(`role_group_id`) references role_groups(`role_group_id`)
) engine=InnoDB;
These conditions must be satisfied to not get error 150 re ALTER TABLE ADD FOREIGN KEY:
The Parent table must exist before you define a foreign key to reference it. You must define the tables in the right order: Parent table first, then the Child table. If both tables references each other, you must create one table without FK constraints, then create the second table, then add the FK constraint to the first table with ALTER TABLE.
The two tables must both support foreign key constraints, i.e. ENGINE=InnoDB. Other storage engines silently ignore foreign key definitions, so they return no error or warning, but the FK constraint is not saved.
The referenced columns in the Parent table must be the left-most columns of a key. Best if the key in the Parent is PRIMARY KEY or UNIQUE KEY.
The FK definition must reference the PK column(s) in the same order as the PK definition. For example, if the FK REFERENCES Parent(a,b,c) then the Parent's PK must not be defined on columns in order (a,c,b).
The PK column(s) in the Parent table must be the same data type as the FK column(s) in the Child table. For example, if a PK column in the Parent table is UNSIGNED, be sure to define UNSIGNED for the corresponding column in the Child table field.
Exception: length of strings may be different. For example, VARCHAR(10) can reference VARCHAR(20) or vice versa.
Any string-type FK column(s) must have the same character set and collation as the corresponding PK column(s).
If there is data already in the Child table, every value in the FK column(s) must match a value in the Parent table PK column(s). Check this with a query like:
SELECT COUNT(*) FROM Child LEFT OUTER JOIN Parent ON Child.FK = Parent.PK
WHERE Parent.PK IS NULL;
This must return zero (0) unmatched values. Obviously, this query is an generic example; you must substitute your table names and column names.
Neither the Parent table nor the Child table can be a TEMPORARY table.
Neither the Parent table nor the Child table can be a PARTITIONED table.
If you declare a FK with the ON DELETE SET NULL option, then the FK column(s) must be nullable.
If you declare a constraint name for a foreign key, the constraint name must be unique in the whole schema, not only in the table in which the constraint is defined. Two tables may not have their own constraint with the same name.
If there are any other FK's in other tables pointing at the same field you are attempting to create the new FK for, and they are malformed (i.e. different collation), they will need to be made consistent first. This may be a result of past changes where SET FOREIGN_KEY_CHECKS = 0; was utilized with an inconsistent relationship defined by mistake. See #andrewdotn's answer below for instructions on how to identify these problem FK's.
MySQL’s generic “errno 150” message “means that a foreign key constraint was not correctly formed.” As you probably already know if you are reading this page, the generic “errno: 150” error message is really unhelpful. However:
You can get the actual error message by running SHOW ENGINE INNODB STATUS; and then looking for LATEST FOREIGN KEY ERROR in the output.
For example, this attempt to create a foreign key constraint:
CREATE TABLE t1
(id INTEGER);
CREATE TABLE t2
(t1_id INTEGER,
CONSTRAINT FOREIGN KEY (t1_id) REFERENCES t1 (id));
fails with the error Can't create table 'test.t2' (errno: 150). That doesn’t tell anyone anything useful other than that it’s a foreign key problem. But run SHOW ENGINE INNODB STATUS; and it will say:
------------------------
LATEST FOREIGN KEY ERROR
------------------------
130811 23:36:38 Error in foreign key constraint of table test/t2:
FOREIGN KEY (t1_id) REFERENCES t1 (id)):
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.
It says that the problem is it can’t find an index. SHOW INDEX FROM t1 shows that there aren’t any indexes at all for table t1. Fix that by, say, defining a primary key on t1, and the foreign key constraint will be created successfully.
Make sure that the properties of the two fields you are trying to link with a constraint are exactly the same.
Often, the 'unsigned' property on an ID column will catch you out.
ALTER TABLE `dbname`.`tablename` CHANGE `fieldname` `fieldname` int(10) UNSIGNED NULL;
What's the current state of your database when you run this script? Is it completely empty? Your SQL runs fine for me when creating a database from scratch, but errno 150 usually has to do with dropping & recreating tables that are part of a foreign key. I'm getting the feeling you're not working with a 100% fresh and new database.
If you're erroring out when "source"-ing your SQL file, you should be able to run the command "SHOW ENGINE INNODB STATUS" from the MySQL prompt immediately after the "source" command to see more detailed error info.
You may want to check out the manual entry too:
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. If MySQL reports an error number 1005 from a CREATE TABLE statement, and the error message refers to error 150, table creation failed because a foreign key constraint was not correctly formed.
— MySQL 5.1 reference manual.
For people who are viewing this thread with the same problem:
There are a lot of reasons for getting errors like this. For a fairly complete list of causes and solutions of foreign key errors in MySQL (including those discussed here), check out this link:
MySQL Foreign Key Errors and Errno 150
For others that find this SO entry via Google: Be sure that you aren't trying to do a SET NULL action on a foreign key (to be) column defined as "NOT NULL." That caused great frustration until I remembered to do a CHECK ENGINE INNODB STATUS.
Definitely it is not the case but I found this mistake pretty common and unobvious. The target of a FOREIGN KEY could be not PRIMARY KEY. Te answer which become useful for me is:
A FOREIGN KEY always must be pointed to a PRIMARY KEY true field of other table.
CREATE TABLE users(
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(40));
CREATE TABLE userroles(
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT NOT NULL,
FOREIGN KEY(user_id) REFERENCES users(id));
As pointed by #andrewdotn the best way is to see the detailed error(SHOW ENGINE INNODB STATUS;) instead of just an error code.
One of the reasons could be that an index already exists with the same name, may be in another table. As a practice, I recommend prefixing table name before the index name to avoid such collisions. e.g. instead of idx_userId use idx_userActionMapping_userId.
Please make sure at first that
you are using InnoDB tables.
field for FOREIGN KEY has the same type and length (!) as source field.
I had the same trouble and I've fixed it. I had unsigned INT for one field and just integer for other field.
Helpful tip, use SHOW WARNINGS; after trying your CREATE query and you will receive the error as well as the more detailed warning:
---------------------------------------------------------------------------------------------------------+
| Level | Code | Message |
+---------+------+-------------------------------------------------------------------------- -------------------------------------------------------------------------------------------- ---------------+
| Warning | 150 | Create table 'fakeDatabase/exampleTable' with foreign key constraint failed. There is no index in the referenced table where the referenced columns appear as the first columns.
|
| Error | 1005 | Can't create table 'exampleTable' (errno:150) |
+---------+------+-------------------------------------------------------------------------- -------------------------------------------------------------------------------------------- ---------------+
So in this case, time to re-create my table!
This is usually happening when you try to source file into existing database.
Drop all the tables first (or the DB itself).
And then source file with SET foreign_key_checks = 0; at the beginning and SET foreign_key_checks = 1; at the end.
I've found another reason this fails... case sensitive table names.
For this table definition
CREATE TABLE user (
userId int PRIMARY KEY AUTO_INCREMENT,
username varchar(30) NOT NULL
) ENGINE=InnoDB;
This table definition works
CREATE TABLE product (
id int PRIMARY KEY AUTO_INCREMENT,
userId int,
FOREIGN KEY fkProductUser1(userId) REFERENCES **u**ser(userId)
) ENGINE=InnoDB;
whereas this one fails
CREATE TABLE product (
id int PRIMARY KEY AUTO_INCREMENT,
userId int,
FOREIGN KEY fkProductUser1(userId) REFERENCES User(userId)
) ENGINE=InnoDB;
The fact that it worked on Windows and failed on Unix took me a couple of hours to figure out. Hope that helps someone else.
MySQL Workbench 6.3 for Mac OS.
Problem: errno 150 on table X when trying to do Forward Engineering on a DB diagram, 20 out of 21 succeeded, 1 failed. If FKs on table X were deleted, the error moved to a different table that wasn't failing before.
Changed all tables engine to myISAM and it worked just fine.
Also worth checking that you aren't accidentally operating on the wrong database. This error will occur if the foreign table does not exist. Why does MySQL have to be so cryptic?
Make sure that the foreign keys are not listed as unique in the parent. I had this same problem and I solved it by demarcating it as not unique.
In my case it was due to the fact that the field that was a foreign key field had a too long name, ie. foreign key (some_other_table_with_long_name_id). Try sth shorter. Error message is a bit misleading in that case.
Also, as #Jon mentioned earlier - field definitions have to be the same (watch out for unsigned subtype).
(Side notes too big for a Comment)
There is no need for an AUTO_INCREMENT id in a mapping table; get rid of it.
Change the PRIMARY KEY to (role_id, role_group_id) (in either order). This will make accesses faster.
Since you probably want to map both directions, also add an INDEX with those two columns in the opposite order. (There is no need to make it UNIQUE.)
More tips: http://mysql.rjweb.org/doc.php/index_cookbook_mysql#speeding_up_wp_postmeta
When the foreign key constraint is based on varchar type, then in addition to the list provided by marv-el the target column must have an unique constraint.
execute below line before creating table :
SET FOREIGN_KEY_CHECKS = 0;
FOREIGN_KEY_CHECKS option specifies whether or not to check foreign key constraints for InnoDB tables.
-- Specify to check foreign key constraints (this is the default)
SET FOREIGN_KEY_CHECKS = 1;
 
-- Do not check foreign key constraints
SET FOREIGN_KEY_CHECKS = 0;
When to Use :
Temporarily disabling referential constraints (set FOREIGN_KEY_CHECKS to 0) is useful when you need to re-create the tables and load data in any parent-child order
I encountered the same problem, but I check find that I hadn't the parent table. So I just edit the parent migration in front of the child migration. Just do it.

mariadb not letting me add a foreign key [duplicate]

I am trying to create a table in MySQL with two foreign keys, which reference the primary keys in 2 other tables, but I am getting an errno: 150 error and it will not create the table.
Here is the SQL for all 3 tables:
CREATE TABLE role_groups (
`role_group_id` int(11) NOT NULL `AUTO_INCREMENT`,
`name` varchar(20),
`description` varchar(200),
PRIMARY KEY (`role_group_id`)
) ENGINE=InnoDB;
CREATE TABLE IF NOT EXISTS `roles` (
`role_id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(50),
`description` varchar(200),
PRIMARY KEY (`role_id`)
) ENGINE=InnoDB;
create table role_map (
`role_map_id` int not null `auto_increment`,
`role_id` int not null,
`role_group_id` int not null,
primary key(`role_map_id`),
foreign key(`role_id`) references roles(`role_id`),
foreign key(`role_group_id`) references role_groups(`role_group_id`)
) engine=InnoDB;
These conditions must be satisfied to not get error 150 re ALTER TABLE ADD FOREIGN KEY:
The Parent table must exist before you define a foreign key to reference it. You must define the tables in the right order: Parent table first, then the Child table. If both tables references each other, you must create one table without FK constraints, then create the second table, then add the FK constraint to the first table with ALTER TABLE.
The two tables must both support foreign key constraints, i.e. ENGINE=InnoDB. Other storage engines silently ignore foreign key definitions, so they return no error or warning, but the FK constraint is not saved.
The referenced columns in the Parent table must be the left-most columns of a key. Best if the key in the Parent is PRIMARY KEY or UNIQUE KEY.
The FK definition must reference the PK column(s) in the same order as the PK definition. For example, if the FK REFERENCES Parent(a,b,c) then the Parent's PK must not be defined on columns in order (a,c,b).
The PK column(s) in the Parent table must be the same data type as the FK column(s) in the Child table. For example, if a PK column in the Parent table is UNSIGNED, be sure to define UNSIGNED for the corresponding column in the Child table field.
Exception: length of strings may be different. For example, VARCHAR(10) can reference VARCHAR(20) or vice versa.
Any string-type FK column(s) must have the same character set and collation as the corresponding PK column(s).
If there is data already in the Child table, every value in the FK column(s) must match a value in the Parent table PK column(s). Check this with a query like:
SELECT COUNT(*) FROM Child LEFT OUTER JOIN Parent ON Child.FK = Parent.PK
WHERE Parent.PK IS NULL;
This must return zero (0) unmatched values. Obviously, this query is an generic example; you must substitute your table names and column names.
Neither the Parent table nor the Child table can be a TEMPORARY table.
Neither the Parent table nor the Child table can be a PARTITIONED table.
If you declare a FK with the ON DELETE SET NULL option, then the FK column(s) must be nullable.
If you declare a constraint name for a foreign key, the constraint name must be unique in the whole schema, not only in the table in which the constraint is defined. Two tables may not have their own constraint with the same name.
If there are any other FK's in other tables pointing at the same field you are attempting to create the new FK for, and they are malformed (i.e. different collation), they will need to be made consistent first. This may be a result of past changes where SET FOREIGN_KEY_CHECKS = 0; was utilized with an inconsistent relationship defined by mistake. See #andrewdotn's answer below for instructions on how to identify these problem FK's.
MySQL’s generic “errno 150” message “means that a foreign key constraint was not correctly formed.” As you probably already know if you are reading this page, the generic “errno: 150” error message is really unhelpful. However:
You can get the actual error message by running SHOW ENGINE INNODB STATUS; and then looking for LATEST FOREIGN KEY ERROR in the output.
For example, this attempt to create a foreign key constraint:
CREATE TABLE t1
(id INTEGER);
CREATE TABLE t2
(t1_id INTEGER,
CONSTRAINT FOREIGN KEY (t1_id) REFERENCES t1 (id));
fails with the error Can't create table 'test.t2' (errno: 150). That doesn’t tell anyone anything useful other than that it’s a foreign key problem. But run SHOW ENGINE INNODB STATUS; and it will say:
------------------------
LATEST FOREIGN KEY ERROR
------------------------
130811 23:36:38 Error in foreign key constraint of table test/t2:
FOREIGN KEY (t1_id) REFERENCES t1 (id)):
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.
It says that the problem is it can’t find an index. SHOW INDEX FROM t1 shows that there aren’t any indexes at all for table t1. Fix that by, say, defining a primary key on t1, and the foreign key constraint will be created successfully.
Make sure that the properties of the two fields you are trying to link with a constraint are exactly the same.
Often, the 'unsigned' property on an ID column will catch you out.
ALTER TABLE `dbname`.`tablename` CHANGE `fieldname` `fieldname` int(10) UNSIGNED NULL;
What's the current state of your database when you run this script? Is it completely empty? Your SQL runs fine for me when creating a database from scratch, but errno 150 usually has to do with dropping & recreating tables that are part of a foreign key. I'm getting the feeling you're not working with a 100% fresh and new database.
If you're erroring out when "source"-ing your SQL file, you should be able to run the command "SHOW ENGINE INNODB STATUS" from the MySQL prompt immediately after the "source" command to see more detailed error info.
You may want to check out the manual entry too:
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. If MySQL reports an error number 1005 from a CREATE TABLE statement, and the error message refers to error 150, table creation failed because a foreign key constraint was not correctly formed.
— MySQL 5.1 reference manual.
For people who are viewing this thread with the same problem:
There are a lot of reasons for getting errors like this. For a fairly complete list of causes and solutions of foreign key errors in MySQL (including those discussed here), check out this link:
MySQL Foreign Key Errors and Errno 150
For others that find this SO entry via Google: Be sure that you aren't trying to do a SET NULL action on a foreign key (to be) column defined as "NOT NULL." That caused great frustration until I remembered to do a CHECK ENGINE INNODB STATUS.
Definitely it is not the case but I found this mistake pretty common and unobvious. The target of a FOREIGN KEY could be not PRIMARY KEY. Te answer which become useful for me is:
A FOREIGN KEY always must be pointed to a PRIMARY KEY true field of other table.
CREATE TABLE users(
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(40));
CREATE TABLE userroles(
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT NOT NULL,
FOREIGN KEY(user_id) REFERENCES users(id));
As pointed by #andrewdotn the best way is to see the detailed error(SHOW ENGINE INNODB STATUS;) instead of just an error code.
One of the reasons could be that an index already exists with the same name, may be in another table. As a practice, I recommend prefixing table name before the index name to avoid such collisions. e.g. instead of idx_userId use idx_userActionMapping_userId.
Please make sure at first that
you are using InnoDB tables.
field for FOREIGN KEY has the same type and length (!) as source field.
I had the same trouble and I've fixed it. I had unsigned INT for one field and just integer for other field.
Helpful tip, use SHOW WARNINGS; after trying your CREATE query and you will receive the error as well as the more detailed warning:
---------------------------------------------------------------------------------------------------------+
| Level | Code | Message |
+---------+------+-------------------------------------------------------------------------- -------------------------------------------------------------------------------------------- ---------------+
| Warning | 150 | Create table 'fakeDatabase/exampleTable' with foreign key constraint failed. There is no index in the referenced table where the referenced columns appear as the first columns.
|
| Error | 1005 | Can't create table 'exampleTable' (errno:150) |
+---------+------+-------------------------------------------------------------------------- -------------------------------------------------------------------------------------------- ---------------+
So in this case, time to re-create my table!
This is usually happening when you try to source file into existing database.
Drop all the tables first (or the DB itself).
And then source file with SET foreign_key_checks = 0; at the beginning and SET foreign_key_checks = 1; at the end.
I've found another reason this fails... case sensitive table names.
For this table definition
CREATE TABLE user (
userId int PRIMARY KEY AUTO_INCREMENT,
username varchar(30) NOT NULL
) ENGINE=InnoDB;
This table definition works
CREATE TABLE product (
id int PRIMARY KEY AUTO_INCREMENT,
userId int,
FOREIGN KEY fkProductUser1(userId) REFERENCES **u**ser(userId)
) ENGINE=InnoDB;
whereas this one fails
CREATE TABLE product (
id int PRIMARY KEY AUTO_INCREMENT,
userId int,
FOREIGN KEY fkProductUser1(userId) REFERENCES User(userId)
) ENGINE=InnoDB;
The fact that it worked on Windows and failed on Unix took me a couple of hours to figure out. Hope that helps someone else.
MySQL Workbench 6.3 for Mac OS.
Problem: errno 150 on table X when trying to do Forward Engineering on a DB diagram, 20 out of 21 succeeded, 1 failed. If FKs on table X were deleted, the error moved to a different table that wasn't failing before.
Changed all tables engine to myISAM and it worked just fine.
Also worth checking that you aren't accidentally operating on the wrong database. This error will occur if the foreign table does not exist. Why does MySQL have to be so cryptic?
Make sure that the foreign keys are not listed as unique in the parent. I had this same problem and I solved it by demarcating it as not unique.
In my case it was due to the fact that the field that was a foreign key field had a too long name, ie. foreign key (some_other_table_with_long_name_id). Try sth shorter. Error message is a bit misleading in that case.
Also, as #Jon mentioned earlier - field definitions have to be the same (watch out for unsigned subtype).
(Side notes too big for a Comment)
There is no need for an AUTO_INCREMENT id in a mapping table; get rid of it.
Change the PRIMARY KEY to (role_id, role_group_id) (in either order). This will make accesses faster.
Since you probably want to map both directions, also add an INDEX with those two columns in the opposite order. (There is no need to make it UNIQUE.)
More tips: http://mysql.rjweb.org/doc.php/index_cookbook_mysql#speeding_up_wp_postmeta
When the foreign key constraint is based on varchar type, then in addition to the list provided by marv-el the target column must have an unique constraint.
execute below line before creating table :
SET FOREIGN_KEY_CHECKS = 0;
FOREIGN_KEY_CHECKS option specifies whether or not to check foreign key constraints for InnoDB tables.
-- Specify to check foreign key constraints (this is the default)
SET FOREIGN_KEY_CHECKS = 1;
 
-- Do not check foreign key constraints
SET FOREIGN_KEY_CHECKS = 0;
When to Use :
Temporarily disabling referential constraints (set FOREIGN_KEY_CHECKS to 0) is useful when you need to re-create the tables and load data in any parent-child order
I encountered the same problem, but I check find that I hadn't the parent table. So I just edit the parent migration in front of the child migration. Just do it.

Foreign key not working in MySQL: Why can I INSERT a value that's not in the foreign column?

I've created a table in MySQL:
CREATE TABLE actions ( A_id int NOT NULL AUTO_INCREMENT,
type ENUM('rate','report','submit','edit','delete') NOT NULL,
Q_id int NOT NULL,
U_id int NOT NULL,
date DATE NOT NULL,
time TIME NOT NULL,
rate tinyint(1),
PRIMARY KEY (A_id),
CONSTRAINT fk_Question FOREIGN KEY (Q_id) REFERENCES questions(P_id),
CONSTRAINT fk_User FOREIGN KEY (U_id) REFERENCES users(P_id));
This created the table I wanted just fine (although a "DESCRIBE actions;" command showed me that the foreign keys were keys of type MUL, and I'm not sure what this means). However, when I try to enter a Q_id or a U_id that does not exist in the questions or users tables, MySQL still allows these values.
What did I do wrong? How can I prevent a table with a foreign key from accepting invalid data?
UPDATE 1
If I add TYPE=InnoDB to the end, I get an error:
ERROR 1005 (HY000): Can't create table './quotes/actions.frm' (errno: 150)
Why might that happen?
UPDATE 2
I'm told that it's important to enforce data integrity with functional foreign keys, but also that InnoDB should not be used with MySQL. What do you recommend?
I would guess that your default storage engine is MyISAM, which ignores foreign key constraints. It silently accepts the declaration of a foreign key, but does not store the constraint or enforce it subsequently.
However, it does implicitly create an index on the columns you declared for the foreign key. In MySQL, "KEY" is a synonym for "INDEX". That's what's being shown in the DESCRIBE output: an index, but not a constraint.
You are able to insert invalid values to the table right now because there is no constraint. To get a constraint that enforces referential integrity, you must use the InnoDB storage engine:
CREATE TABLE actions (
A_id int NOT NULL AUTO_INCREMENT,
...
CONSTRAINT fk_Question FOREIGN KEY (Q_id) REFERENCES questions(P_id),
CONSTRAINT fk_User FOREIGN KEY (U_id) REFERENCES users(P_id)
) ENGINE=InnoDB;
I've always thought it was a big mistake on MySQL's part to silently ignore foreign key constraint declarations. There's no error or warning that the storage engine doesn't support them.
The same is true for CHECK constraints before MySQL 8.0.16. No storage engine used with MySQL supported CHECK constraints, but the SQL parser accepts them with no complaint. In 8.0.16 and later, InnoDB tables do support CHECK constraints but other storage engines still ignore them.
The errno 150 issue occurs when it cannot create the InnoDB table, because it couldn't make sense of the foreign key constraint. You can get some more information with:
SHOW ENGINE INNODB STATUS;
Some requirements for InnoDB foreign keys:
Referenced table must also be InnoDB.
Referenced table must have an index and a primary key.
SQL data types of FK column and referenced PK column must be identical. For example, INT does not match BIGINT or INT UNSIGNED.
You can change the storage engine of a table that has data in it:
ALTER TABLE actions ENGINE=InnoDB;
This effectively copies the entire MyISAM table to an InnoDB table, then once that succeeds it drops the MyISAM table and renames the new InnoDB table to the name of the former MyISAM table. This is called a "table restructure" and it can be time-consuming, depending on how much data is in the table. A table restructure occurs during ALTER TABLE, even in some cases where it may seem unnecessary.
Re your update 2:
I'm told that it's important to enforce data integrity with functional foreign keys, but also that InnoDB should not be used with MySQL. What do you recommend?
Who told you that? It's absolutely false. InnoDB has better performance than MyISAM (though InnoDB needs more attention to tuning the configuration), InnoDB supports atomic changes, transactions, foreign keys, and InnoDB is much more resistant to corrupting data in a crash.
Unless you're running an old, unsupported version of MySQL (5.0 or earlier) you should use InnoDB as your default storage engine choice, and use MyISAM only if you can demonstrate a specific workload that benefits from MyISAM.
Just to save other's of the hours of headache I've been thru - as giraffa touches upon, ensure #FOREIGN_KEY_CHECKS is set to 1.
SELECT ##FOREIGN_KEY_CHECKS
SET FOREIGN_KEY_CHECKS=1
I know this thread was opened long time ago, but I am posting this message for future users who will look for the answer.
I was having the same problem with foreign key in mysql.
The following thing worked for me.
Parent table:
CREATE TABLE NameSubject (
Autonumber INT NOT NULL AUTO_INCREMENT,
NameorSubject nvarchar(255),
PRIMARY KEY (Autonumber)
) ENGINE=InnoDB;
Child Table:
CREATE TABLE Volumes (
Autonumber INT NOT NULL,
Volume INT,
Pages nvarchar(50),
Reel int,
Illustrations bit,
SSMA_TimeStamp timestamp,
Foreign KEY (Autonumber) references NameSubject(Autonumber)
ON update cascade
)engine=innodb;
"ON update cascade" did the magic for me.
I hope this works for others. Best of luck.
For those who still have problems with mysql ignoring foreign keys constraints and for those who the answers above or in any other related question didn't solve teir puzzle, here is what I found to be the issue.
If you declare your foreign keys as such
id INTEGER UNSIGNED REFERENCES A_Table(id)
Then the foreign key seems to be ignored, to enforce the constraint without (apparently) having to use any of the SET commands, use the following declaration.
id INTEGER UNSIGNED,
CONSTRAINT fk_id FOREIGN KEY (id) REFERENCES A_Table(id)
This way solved the problem for me. Not sure why, as many say the first declaration is only a shorthand to the second variant.
I found the following article. I don't have time to test it out, currently, but it may be helpful:
http://forums.mysql.com/read.php?22,19755,43805
The author,Edwin Dando, says:
both tables must be INNODB. The foreign key field must have an index on it. The foeign key field and the field being referenced must be of the same type (I only use integer) and, after hours of pain, they must be UNSIGNED.
the problem is most likely that questions.p_id and users.p_id are not defined as INT NOT NULL. for foreign keys to work, the definition of the columns on both side of the foreign key must match exactly, with the exception of auto_increment and default.
This answer would have saved me a lot of time if I'd seen it first. Try the following three steps, which I've ordered by frequency of newbie mistakes:
(1) Change the table to be InnodDB by appending "ENGINE=InnoDB" to your "CREATE TABLE" statements.
Other engines, which may be the default, do not support foreign key constraints, but neither do they throw an error or warning telling you they're not supported.
(2) Make sure foreign key constraints are in fact being checked by executing "SET foreign_key_checks = 'ON'"
(3) Append "ON UPDATE CASCADE" to your foreign key declaration.
Note: Make sure that cascading is the behavior you want. There are other options...
As noted, your table have to be InnoDB for FK constraints to be enforced.
I've only run into the 'Can't create table' in the case where I'm trying to create a foreign key constraint where my local column is a different type from the foreign column.
I think some of the folks having this problem might be starting out with some of the sample databases provided on the ORACLE website for MYSQL (e.g. sakila DB). Don't forget to "turn the foreign key constraints back on" at the end of your script (e.g. at the beginning of sakila DB script they are turned OFF)
SET #OLD_UNIQUE_CHECKS=##UNIQUE_CHECKS, UNIQUE_CHECKS=0;
SET #OLD_FOREIGN_KEY_CHECKS=##FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;
SET #OLD_SQL_MODE=##SQL_MODE, SQL_MODE='TRADITIONAL';
create your tables here
then don't forget this:
SET SQL_MODE=#OLD_SQL_MODE;
SET FOREIGN_KEY_CHECKS=#OLD_FOREIGN_KEY_CHECKS;
SET UNIQUE_CHECKS=#OLD_UNIQUE_CHECKS;
Well, my guess is somehow the "Skip creation of FORIEN KEYS" option is checked, it can happen in the "options" section of the "Forward Engineering" process.