I created my MySQL database using phpMyAdmin 3.5.8.1deb1 in Ubuntu.
Instead of that all my tables are InnoDB, I can't add a foreign key, and this is an example:
ALTER TABLE element ADD CONSTRAINT FK_element_id_user FOREIGN KEY (id_user) REFERENCES user(id) ON DELETE SET NULL ON UPDATE CASCADE;
When I run this script I get this error :
#1005 - Can't create table 'tpw.#sql-4d8_e2' (errno: 150) (Details...)
When I click on details I get this :
InnoDB Documentation Supports transactions, row-level locking, and foreign keys
I tried to add the FK manually in the relation view
There could be a couple of things going one here. Here are some things to look for:
Do the data types of each field between the tables match?
Are both both tables using the same MySQL engine?
Here is a good resource to help you debug this issue further.
Excerpt from the resource linked to above:
1) The two key fields type and/or size is not an exact match. For example, if one is INT(10) the key field needs to be INT(10) as well and not INT(11) or TINYINT. You may want to confirm the field size using SHOW CREATE TABLE because Query Browser will sometimes visually show just INTEGER for both INT(10) and INT(11). You should also check that one is not SIGNED and the other is UNSIGNED. They both need to be exactly the same.
2) One of the key field that you are trying to reference does not have an index and/or is not a primary key. If one of the fields in the relationship is not a primary key, you must create an index for that field.
3) The foreign key name is a duplicate of an already existing key. Check that the name of your foreign key is unique within your database. Just add a few random characters to the end of your key name to test for this.
4) One or both of your tables is a MyISAM table. In order to use foreign keys, the tables must both be InnoDB. (Actually, if both tables are MyISAM then you won’t get an error message – it just won’t create the key.) In Query Browser, you can specify the table type.
5) You have specified a cascade ON DELETE SET NULL, but the relevant key field is set to NOT NULL. You can fix this by either changing your cascade or setting the field to allow NULL values.
6) Make sure that the Charset and Collate options are the same both at the table level as well as individual field level for the key columns.
7) You have a default value (ie default=0) on your foreign key column.
8) One of the fields in the relationship is part of a combination (composite) key and does not have it’s own individual index. Even though the field has an index as part of the composite key, you must create a separate index for only that key field in order to use it in a constraint.
9) You have a syntax error in your ALTER statement or you have mistyped one of the field names in the relationship.
10) The name of your foreign key exceeds the max length of 64 chars.
User.ID has to be declared as an INDEX
Related
There are plenty of questions regarding this error but I can't seem to find any similar scenario to what I have.
My 1st table (users):
My 2nd table (colleges):
I am trying to alter 1st table and add a foreign key that references id of a 2nd table:
ALTER TABLE users
ADD CONSTRAINT FOREIGN KEY (collegelinkId)
REFERENCES databaseName.colleges (id);
Which fails with error (errno: 150 "Foreign key constraint is incorrectly formed").
The only parameter that is different between these two tables is auto_increment. However, I can not add auto_increment to my users table collegelinkId column since its id is already set to auto_increment.
We would expect to see this error if the types of the primary and foreign key did not match exactly. While both appear to be integer with a width of 1, my guess here is that one of the INT columns in the key relationship is unsigned, while the other is signed. A possible fix would be to make both columns unsigned:
ALTER TABLE users MODIFY collegelinkId INT(10) UNSIGNED NOT NULL;
ALTER TABLE college MODIFY id INT(10) UNSIGNED NOT NULL;
Edit:
I was wrong, as evidenced by your latest comments under my answer. Another possibility is that you created your two tables using different database engines. For example, if you created users using InnoDB, but college using MyISAM, you could still get this error. To fix this, change the engine(s) on the tables to the same type.
Note that yet another possibility would be that the two columns had different collations. But, that's really a moot point here, since both columns are numeric, not text.
Since the columns are of the same type, it's worth to check the engine type as #Tim Biegeleisen suggested.
Changing engine type fixed the issue.
ALTER TABLE users
ENGINE=InnoDB;
Verify that the datatypes match (except for PRIMARY KEY).
Verify that both tables are ENGINE=InnoDB.
Even after that, error 150 can still occur. 3 ways around it:
Disable FKs while creating the tables, then re-enable.
CREATE TABLEs without FKs, then ALTER ... ADD ... FKs
Be sure the do the CREATEs in just the right order.
A side note: In INT(2), the (2) is irrelevant. All INTs are 4 bytes.
So I'm attempting to add a new foreign key to one of my tables as such:
ALTER TABLE `UserTransactions`.`ExpenseBackTransactions`
ADD CONSTRAINT `FK_EBTx_CustomAccountID`
FOREIGN KEY (`CustomAccountID` )
REFERENCES `UserTransactions`.`CustomAccounts` (`CustomAccountID`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
ADD INDEX `FK_EBTx_CustomAccountID` (`CustomAccountID` ASC) ;
and I keep getting the following error:
Error Code: 1005
Can't create table './UserTransactions/#sql-187a_29.frm' (errno: 150)
I've done quite a bit of changes in the past to this and other tables, and this is the first time I've run into this issue. Any ideas what is causing it?
UPDATE
My SHOW INNODB STATUS error:
------------------------
LATEST FOREIGN KEY ERROR
------------------------
110525 15:56:36 Error in foreign key constraint of table UserTransactions/#sql-187a_2c:
FOREIGN KEY (`CustomAccountID` )
REFERENCES `UserTransactions`.`CustomAccounts` (`CustomAccountID` )
ON DELETE NO ACTION
ON UPDATE NO ACTION
, ADD INDEX `FK_EBTx_CustomAccountID` (`CustomAccountID` ASC):
Cannot resolve table name close to:
(`CustomAccountID` )
ON DELETE NO ACTION
ON UPDATE NO ACTION
, ADD INDEX `FK_EBTx_CustomAccountID` (`CustomAccountID` ASC)
There's a nice checklist here.
Below is a running list of known causes that people have reported for the dreaded errno 150:
The two key fields type and/or size is not an exact match. For example, if one is INT(10) the key field needs to be INT(10) as well and not INT(11) or TINYINT. You may want to confirm the field size using SHOW CREATE TABLE because Query Browser will sometimes visually show just INTEGER for both INT(10) and INT(11). You should also check that one is not SIGNED and the other is UNSIGNED. They both need to be exactly the same. (More about signed vs unsigned here).
One of the key field that you are trying to reference does not have an index and/or is not a primary key. If one of the fields in the relationship is not a primary key, you must create an index for that field. (thanks to Venkatesh and Erichero and Terminally Incoherent for this tip)
The foreign key name is a duplicate of an already existing key. Check that the name of your foreign key is unique within your database. Just add a few random characters to the end of your key name to test for this. (Thanks to Niels for this tip)
One or both of your tables is a MyISAM table. In order to use foreign keys, the tables must both be InnoDB. (Actually, if both tables are MyISAM then you won’t get an error message – it just won’t create the key.) In Query Browser, you can specify the table type.
You have specified a cascade ON DELETE SET NULL, but the relevant key field is set to NOT NULL. You can fix this by either changing your cascade or setting the field to allow NULL values. (Thanks to Sammy and J Jammin)
Make sure that the Charset and Collate options are the same both at the table level as well as individual field level for the key columns. (Thanks to FRR for this tip)
You have a default value (ie default=0) on your foreign key column (Thanks to Omar for the tip)
One of the fields in the relationship is part of a combination (composite) key and does not have its own individual index. Even though the field has an index as part of the composite key, you must create a separate index for only that key field in order to use it in a constraint. (Thanks to Alex for this tip)
You have a syntax error in your ALTER statement or you have mistyped one of the field names in the relationship (Thanks to Christian & Mateo for the tip)
The name of your foreign key exceeds the max length of 64 chars. (Thanks to Nyleta for the tip)
In my experience, the errno: 150 usually indicates that the data types of the FOREIGN KEY column in the key table and relating table are not identical. Make sure that CustomAccounts.CustomAccountID and ExpenseBackTransactions.CustomAccountIDare the exact same type, including UNSIGNED if it applies.
If that doesn't help, please post the SHOW CREATE TABLE ExpenseBackTransactions; and SHOW CREATE TABLE CustomAccounts;
Catch 22. Foreign keys need indexes. MySQL doesn't order this query so that the index exists at the time it does it foreign key checks. Thus, first create the index, then add the foreign key in 2 separate queries.
I used MySQL workbench to add a foreign key in a table, but some strange error happened, this is the SQL statement:
ALTER TABLE `tansung`.`Declaration` ADD COLUMN `goodsId` INT(11) NOT NULL AFTER `declarationId` ,
ADD CONSTRAINT `goodsId`
FOREIGN KEY (`goodsId` )
REFERENCES `tansung`.`Goods` (`goodsId` )
ON DELETE NO ACTION
ON UPDATE NO ACTION
, ADD INDEX `goodsId` (`goodsId` ASC) ;
When i click apply, the surprise comes out!
ERROR 1005: Can't create table 'tansung.#sql-1b10_1' (errno: 150)
SQL Statement:
ALTER TABLE `tansung`.`Declaration` ADD COLUMN `goodsId` INT(11) NOT NULL AFTER `declarationId` ,
ADD CONSTRAINT `goodsId`
FOREIGN KEY (`goodsId` )
REFERENCES `tansung`.`Goods` (`goodsId` )
ON DELETE NO ACTION
ON UPDATE NO ACTION
, ADD INDEX `goodsId` (`goodsId` ASC)
ERROR: Error when running failback script. Details follow.
ERROR 1050: Table 'Declaration' already exists
SQL Statement:
CREATE TABLE `Declaration` (
`declarationId` int(11) NOT NULL,
PRIMARY KEY (`declarationId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
I can't find out any mistake in logic, even can't understand the error, please give me a help.
All foreign key names throughout the database must be unique. If you already have a foreign key named 'goodsId', even on another table, you will receive this error.
If the related columns do not have exactly the same type (e.g. INT) and constraints (UNIQUE and such), you will receive that error.
It can happen because of many reasons. Following are some of the common reasons. You can also say syntactical errors, because of which these kinds of error are thrown.
If the FK (Foreign Key) table Engine is using MyISAM and PK (Primary Key) table Engine is using InnoDB. MyISAM does not support foreign key constraints. So, you might want to converting your linking table to InnoDB.
All foreign key names throughout the database must be unique. If you already have a foreign key constraint with the same name, even on another table, you will receive this error.
If the related columns do not have exactly the same data typetype (e.g. INT) and constraints (UNIQUE and such), you will receive that error.
I'm getting this error when the table being linked to (in your case, Goods) is stored using MyISAM, and the table you're adding the index to (in your case, Declarations) is stored using InnoDB.
You can tell this from the files in the database directory. MyISAM tables will have files like:
table_name.frm
table_name.MYD
table_name.MYI
The InnoDB table will just have:
table_name.frm
MyISAM does not support foreign key constraints. I would suggest converting your Goods table to InnoDB (though, have a look at the documentation first and do some basic research):
ALTER TABLE Goods ENGINE=INNODB;
After making this change, my ADD INDEX operation completed successfully.
Like the others have said, first make sure the types of the two columns are the same and the database supports it. After that, make sure that the columns that hold the keys to the other tables are valid.
I had a problem where I was adding the constraint to an existing column with data in it, and that data didn't match any of the primary keys in the other table so the attempt to create the relationship would fail. Fixing it involved updating all the columns to make sure my column data matched up with the constraint I was trying to make.
I discovered that when trying to do this in phpMyAdmin that tables that had a hyphen in the name would only allow one FK and then give errors. I have no idea why but it was easy enough to work around I simply remade the
CREATE TABLE `something_new` LIKE `something-old`;
DROP TABLE `something-old`;
YMMV.
The type definitions of Goods.goodsId and Declarations.goodsId must be identical, or you will get the errno: 150.
Make sure they are both the same data type, which looks to be goodsId INT(11) NOT NULL in the Declarations table. What is the CREATE TABLE statement for Goods?
I had the same problem. It seems that there was some data in the child table that was not present in the parent table. You can do an outer join to see the differences and you can assign a valid id for non-matching rows or delete them:
DELETE FROM books
WHERE NOT EXISTS (
SELECT * FROM users
WHERE books.user_id = users.id
)
Errno 150 has a lot of causes. If you have SUPER privileges, you should try using
SHOW ENGINE INNODB STATUS
and that will tell you what the cause was. If you don't have SUPER privileges, you need to just go through all the possible causes. You can find how to use the SHOW INNODB STATUS and a list of all the causes here:
MySQL Foreign Key Errors and Errno 150
When I got that error it was becuase I was trying to update a table that already had data int it and the data didn't meet the FK restrictions.
A fourth possible problem (to the three proposed by abhijitcaps) is that you didn't make the column you are referencing to a primary key.
The below set of commands:
alter table opportunities add column ownerId int null;
alter table opportunities add foreign key (ownerId) references users (id) on delete set null on update cascade;
Yields an error like this:
Error in foreign key constraint of table taous/#sql-318c_27:
There is no index in table "taous"."#sql-318c_27" where the columns appear
as the first columns. Constraint:
foreign key (ownerId) references users (id) on delete set null on update cascade
;
So I understand that an index is lacking on the referenced column
Now, the mysql documentation for foreign key constraints states:
InnoDB requires indexes on foreign keys and referenced keys so that foreign key checks can be fast and not require a table scan. In the referencing table, there must be an index where the foreign key columns are listed as the first columns in the same order. Such an index is created on the referencing table automatically if it does not exist. (This is in contrast to some older versions, in which indexes had to be created explicitly or the creation of foreign key constraints would fail.) index_name, if given, is used as described previously.
I run mysql 5.1 (xampp, windows) So I expect the columns to be indexed automatically on creation of a foreign key.
Any idea why can the auto indexing fail?
One more point:
The error only happens when the sql commands are run through PDO (a db update tool). When run directly in mysql console, no problems.
Thanks
Gidi
My understanding is that the auto-indexing is on the referencing table and not the referenced table.
In your case, the auto-indexing would add an index to ownerId in opportunities... except it doesn't need to, since you already did this.
I don't quite understand where "taous"."#sql-318c_27" comes from, but assuming that it relates to the users table, I believe the error is complaining that id is not indexed.
Another cause of this error could be that the types of the the referenced and referencing table columns do not match.
For example if the the ownerId column of the opportunities table is an INT but the Id column of the users is any type other than INT
That doesn't explain why it would work with the console and not a PDO however, but maybe this helps someone else down the line.
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.