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.
Related
I understand MySQL is automatically placing an index on every table's primary and foreign keys.
However, I would like to personally create my own indices on the foreign keys as I want to execute a query with hibernate showing the difference in time when I execute it with and without indices.
Is there any option in MySQL Workbench to disable it's auto indexing feature?
No you cannot disable the auto index creation of index on tables. This is a inbuilt feature which is added in MySql.
However if you want you can drop the index like this:
DROP INDEX index_name ON tbl_name
and then create it again.
From InnoDB and FOREIGN KEY Constraints
"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."
No, these indexes are always created. Otherwise, every UPDATE or INSERT that modifies these columns would have to perform a full table scan, to ensure that the primary key is unique and the foreign key has a valid reference.
Regarding foreign keys, the documentation says:
MySQL 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.
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
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.
Does MySQL index foreign key columns automatically?
Yes, but only on innodb. Innodb is currently the only shipped table format that has foreign keys implemented.
Apparently an index is created automatically as specified in the link robert has posted.
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.
InnoDB and FOREIGN KEY Constraints
For those who are looking for quote from 5.7 docs:
MySQL 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 index might be silently dropped later, if you create
another index that can be used to enforce the foreign key constraint.
index_name, if given, is used as described previously.
You don't get the index automatically if you do an ALTER TABLE (instead of CREATE TABLE), at least according to the docs (the link is for 5.1 but it's the same for 5.5):
[...] When you add a foreign key constraint to a table using ALTER TABLE, remember to create the required indexes first.
As stated it does for InnoDB. At first I thought it was strange that many other (in particular MS SQL and DB2) doesn't. TableSpace scans are only better than index scans when there are very few table rows - so for the vast majority of cases a foreign key would want to be indexed. Then it kind of hit me - this doesn't necessarily mean it has to be a stand alone (one column) index - where it is in MySQL's automatic FK Index. So, may be that is the reason MS SQL, DB2 (Oracle I'm not sure on) etc leave it up to the DBA; after all multiple indexes on large tables can cause issues with performance and space.
Yes, Innodb provide this. You can put a foreign key name after FOREIGN KEY clause or leave it to let MySQL to create a name for you. MySQL automatically creates an index with the foreign_key_name name.
CONSTRAINT constraint_name
FOREIGN KEY foreign_key_name (columns)
REFERENCES parent_table(columns)
ON DELETE action
ON UPDATE action
It's not possible to get index key automatically use
ALTER TABLE (NAME OF THE TABLE) ADD INDEX (FOREIGN KEY)
Name of the table which you have created for example photographs and FOREIGN KEY for example photograph_id. The code should be like this
ALTER TABLE photographs ADD INDEX (photograph_id);