mySQL - KEY and FOREIGN KEY keywords - mysql

I created my tables in workbench and forward engineered to create my database. When I backed up my database by export/dump, I came across some lines of code for CREATE TABLE that I'm not sure why they look the way they do:
I have CONSTRAINT-FOREIGN KEY()REFERENCES-() for all my foreign key constraints which makes sense. But I also have KEY which seems to be creating an index for some of my foreign keys but not for all of them in many of my tables. I don't know what this KEY line does and why it's this way? In the example below, I have KEY for 2 of my 3 FKs (one of the FKs being a composite FK made up of 3).
After the KEY and CONSTRAINT, sometimes the code just mentions the foreign key name, and some other times it has the format fk_referencingTable_referencedTable1. Accidentally in this example the composite foreign key has this second format, but really it looks like any foreign key (either single or composite) can randomly have either one of these 2 formats? Why is that and should I be concerned about it?
DROP TABLE IF EXISTS `Recommendations`;
/*!40101 SET #saved_cs_client = ##character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `Recommendations` (
`client_SIN` char(9) NOT NULL
`advisor_SIN` char(9) NOT NULL,
`exchange_name` varchar(45) NOT NULL,
`security_tradeName` varchar(45) NOT NULL,
`FSI_name` varchar(45) NOT NULL,
`Date` date DEFAULT NULL,
`Quantity` int(11) DEFAULT NULL,
PRIMARY KEY (`client_SIN`,`advisor_SIN`,`exchange_name`,`security_tradeName`,
`FSI_name`),
KEY `advisor_SIN_idx` (`advisor_SIN`),
KEY `fk_Recommendations_Exchanges_has_Securities1_idx`
(`exchange_name`,`security_tradeName`,`FSI_name`),
CONSTRAINT `advisor_SIN` FOREIGN KEY (`advisor_SIN`)
REFERENCES `Advisors` (`advisor_SIN`)
ON DELETE CASCADE ON UPDATE NO ACTION,
CONSTRAINT `client_SIN` FOREIGN KEY (`client_SIN`)
REFERENCES `Clients` (`client_SIN`)
ON DELETE CASCADE ON UPDATE NO ACTION,
CONSTRAINT `fk_Recommendations_Exchanges_has_Securities1`
FOREIGN KEY (`exchange_name`, `security_tradeName`, `FSI_name`)
REFERENCES `Exchanges_has_Securities` (`Exchanges_exchange_name`,
`Securities_security_tradeName`, `Securities_issuer_name`)
ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Creating a foreign key automatically adds a key for the column(s) in the FK if it's not already indexed. There's no additional KEY for client_SIN because it's the first column in the primary key, and any prefix of a composite index is an index of its own.
I believe the index names you got were assigned by MySQL Workbench. The default in MySQL is to use the first column name as the index name when you don't name an index explicitly. But it looks like MySQL Workbench appends _idx when it creates the index. And if it's creating the index for a foreign key it uses the prefix fk_ as well.

KEY is keyword-statement for index creation (i.e. it is sub-statement). It creates an index, changing the data storage.
FOREIGN KEY is a keyword-rule (yes, this is one keyword despite it consist from two separate words) for consistency checking subsystem, and does not cause any change in data storage itself. But it contains hidden statements - first of them checks does the index where the reference expression is a prefix exists, second creates an index by this expression if the checking fails (i.e. second hidden statement is KEY statement). CONSTRAINT is naming part of FOREIGN KEY rule (if it is absent then the name will be generated automatically).

Related

#1452 - Cannot add or update a child row: a foreign key constraint fails the query is failing [duplicate]

I'm having a bit of a strange problem. I'm trying to add a foreign key to one table that references another, but it is failing for some reason. With my limited knowledge of MySQL, the only thing that could possibly be suspect is that there is a foreign key on a different table referencing the one I am trying to reference.
I've done a SHOW CREATE TABLE query on both tables, sourcecodes_tags is the table with the foreign key, sourcecodes is the referenced table.
CREATE TABLE `sourcecodes` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`user_id` int(11) unsigned NOT NULL,
`language_id` int(11) unsigned NOT NULL,
`category_id` int(11) unsigned NOT NULL,
`title` varchar(40) CHARACTER SET utf8 NOT NULL,
`description` text CHARACTER SET utf8 NOT NULL,
`views` int(11) unsigned NOT NULL,
`downloads` int(11) unsigned NOT NULL,
`time_posted` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `user_id` (`user_id`),
KEY `language_id` (`language_id`),
KEY `category_id` (`category_id`),
CONSTRAINT `sourcecodes_ibfk_3` FOREIGN KEY (`language_id`) REFERENCES `languages` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `sourcecodes_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `sourcecodes_ibfk_2` FOREIGN KEY (`category_id`) REFERENCES `categories` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1
CREATE TABLE `sourcecodes_tags` (
`sourcecode_id` int(11) unsigned NOT NULL,
`tag_id` int(11) unsigned NOT NULL,
KEY `sourcecode_id` (`sourcecode_id`),
KEY `tag_id` (`tag_id`),
CONSTRAINT `sourcecodes_tags_ibfk_1` FOREIGN KEY (`tag_id`) REFERENCES `tags` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=latin1
This is the code that generates the error:
ALTER TABLE sourcecodes_tags ADD FOREIGN KEY (sourcecode_id) REFERENCES sourcecodes (id) ON DELETE CASCADE ON UPDATE CASCADE
Quite likely your sourcecodes_tags table contains sourcecode_id values that no longer exists in your sourcecodes table. You have to get rid of those first.
Here's a query that can find those IDs:
SELECT DISTINCT sourcecode_id FROM
sourcecodes_tags tags LEFT JOIN sourcecodes sc ON tags.sourcecode_id=sc.id
WHERE sc.id IS NULL;
I had the same issue with my MySQL database but finally, I got a solution which worked for me.
Since in my table everything was fine from the mysql point of view(both tables should use InnoDB engine and the datatype of each column should be of the same type which takes part in foreign key constraint).
The only thing that I did was to disable the foreign key check and later on enabled it after performing the foreign key operation.
Steps that I took:
SET foreign_key_checks = 0;
alter table tblUsedDestination add constraint f_operatorId foreign key(iOperatorId) references tblOperators (iOperatorId); Query
OK, 8 rows affected (0.23 sec) Records: 8 Duplicates: 0 Warnings: 0
SET foreign_key_checks = 1;
Use NOT IN to find where constraints are constraining:
SELECT column FROM table WHERE column NOT IN
(SELECT intended_foreign_key FROM another_table)
so, more specifically:
SELECT sourcecode_id FROM sourcecodes_tags WHERE sourcecode_id NOT IN
(SELECT id FROM sourcecodes)
EDIT: IN and NOT IN operators are known to be much faster than the JOIN operators, as well as much easier to construct, and repeat.
Truncate the tables and then try adding the FK Constraint.
I know this solution is a bit awkward but it does work 100%. But I agree that this is not an ideal solution to deal with problem, but I hope it helps.
For me, this problem was a little different and super easy to check and solve.
You must ensure BOTH of your tables are InnoDB. If one of the tables, namely the reference table is a MyISAM, the constraint will fail.
SHOW TABLE STATUS WHERE Name = 't1';
ALTER TABLE t1 ENGINE=InnoDB;
This also happens when setting a foreign key to parent.id to child.column if the child.column has a value of 0 already and no parent.id value is 0
You would need to ensure that each child.column is NULL or has value that exists in parent.id
And now that I read the statement nos wrote, that's what he is validating.
I had the same problem today. I tested for four things, some of them already mentioned here:
Are there any values in your child column that don't exist in the parent column (besides NULL, if the child column is nullable)
Do child and parent columns have the same datatype?
Is there an index on the parent column you are referencing? MySQL seems to require this for performance reasons (http://dev.mysql.com/doc/refman/5.5/en/create-table-foreign-keys.html)
And this one solved it for me: Do both tables have identical collation?
I had one table in UTF-8 and the other in iso-something. That didn't work. After changing the iso-table to UTF-8 collation the constraints could be added without problems. In my case, phpMyAdmin didn't even show the child table in iso-encoding in the dropdown for creating the foreign key constraint.
It seems there is some invalid value for the column line 0 that is not a valid foreign key so MySQL cannot set a foreign key constraint for it.
You can follow these steps:
Drop the column which you have tried to set FK constraint for.
Add it again and set its default value as NULL.
Try to set a foreign key constraint for it again.
I'd the same problem, I checked rows of my tables and found there was some incompatibility with the value of fields that I wanted to define a foreign key. I corrected those value, tried again and the problem was solved.
I end up delete all the data in my table, and run alter again. It works. Not the brilliant one, but it save a lot time, especially your application is still in development stage without any customer data.
try this
SET foreign_key_checks = 0;
ALTER TABLE sourcecodes_tags ADD FOREIGN KEY (sourcecode_id) REFERENCES sourcecodes (id) ON DELETE CASCADE ON UPDATE CASCADE
SET foreign_key_checks = 1;
I had this exact same problem about three different times. In each instance it was because one (or more) of my records did not conform to the new foreign key. You may want to update your existing records to follow the syntax constraints of the foreign key before trying to add the key itself. The following example should generally isolate the problem records:
SELECT * FROM (tablename)
WHERE (candidate key) <> (proposed foreign key value)
AND (candidate key) <> (next proposed foreign key value)
repeat AND (candidate key) <> (next proposed foreign key value) within your query for each value in the foreign key.
If you have a ton of records this can be difficult, but if your table is reasonably small it shouldn't take too long. I'm not super amazing in SQL syntax, but this has always isolated the issue for me.
Empty both your tables' data and run the command. It will work.
I was getting this error when using Laravel and eloquent, trying to make a foreign key link would cause a 1452. The problem was lack of data in the linked table.
Please see here for an example: http://mstd.eu/index.php/2016/12/02/laravel-eloquent-integrity-constraint-violation-1452-foreign-key-constraint/
You just need to answer one question:
Is your table already storing data? (Especially the table included foreign key.)
If the answer is yes, then the only thing you need to do is to delete all the records, then you are free to add any foreign key to your table.
Delete instruction: From child(which include foreign key table) to parent table.
The reason you cannot add in foreign key after data entries is due to the table inconsistency, how are you going to deal with a new foreign key on the former data-filled the table?
If the answer is no, then follow other instructions.
I was readying this solutions and this example may help.
My database have two tables (email and credit_card) with primary keys for their IDs. Another table (client) refers to this tables IDs as foreign keys. I have a reason to have the email apart from the client data.
First I insert the row data for the referenced tables (email, credit_card) then you get the ID for each, those IDs are needed in the third table (client).
If you don't insert first the rows in the referenced tables, MySQL wont be able to make the correspondences when you insert a new row in the third table that reference the foreign keys.
If you first insert the referenced rows for the referenced tables, then the row that refers to foreign keys, no error occurs.
Hope this helps.
Make sure the value is in the other table otherwise you will get this error, in the assigned corresponding column.
So if it is assigned column is assigned to a row id of another table , make sure there is a row that is in the table otherwise this error will appear.
you can try this exapmple
START TRANSACTION;
SET foreign_key_checks = 0;
ALTER TABLE `job_definers` ADD CONSTRAINT `job_cities_foreign` FOREIGN KEY
(`job_cities`) REFERENCES `drop_down_lists`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
SET foreign_key_checks = 1;
COMMIT;
Note : if you are using phpmyadmin just uncheck Enable foreign key checks
as example
hope this soloution fix your problem :)
UPDATE sourcecodes_tags
SET sourcecode_id = NULL
WHERE sourcecode_id NOT IN (
SELECT id FROM sourcecodes);
should help to get rid of those IDs. Or if null is not allowed in sourcecode_id, then remove those rows or add those missing values to the sourcecodes table.
I had the same problem and found solution, placing NULL instead of NOT NULL on foreign key column. Here is a query:
ALTER TABLE `db`.`table1`
ADD COLUMN `col_table2_fk` INT UNSIGNED NULL,
ADD INDEX `col_table2_fk_idx` (`col_table2_fk` ASC),
ADD CONSTRAINT `col_table2_fk1`
FOREIGN KEY (`col_table2_fk`)
REFERENCES `db`.`table2` (`table2_id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION;
MySQL has executed this query!
In my case, I created a new table with the same structure, created the relationships with the other tables, then extracted the data in CSV from the old table that has the problem, then imported the CSV to the new table and disabled foreign key checking and disabled import interruption, all my data are inserted to the new table that has no problem successfully, then deleted the old table.
It worked for me.

SQL Error (1215): Cannot add foreign key constraint

CREATE TABLE `profilePic` (
`ClientID` VARCHAR(255) NOT NULL,
PRIMARY KEY (`ClientID`),
CONSTRAINT `FK__user_details` FOREIGN KEY (`ClientID`) REFERENCES `user_details` (`ClientID`) ON UPDATE CASCADE ON DELETE CASCADE
)
COLLATE='utf8mb4_unicode_ci'
ENGINE=InnoDB
;
I am trying to add table with foreign key and I got this error, why that happend ?
trying doing new table.
i am trying to put same details on user_details->ClientID and profilePic->ClientID
3.i have already one table call`d userdb and in this table i have ClientID and its foreign key and its work.
The below will fail because the collation is different. Why do I show this? Because the OP didn't.
Note I shrunk the size due to error 1071 on sizing for varchar 255 with that collation and then auto chosen charset.
The point being, if collation is different, it won't work.
CREATE TABLE `user_details` (
`ClientID` VARCHAR(100) NOT NULL,
PRIMARY KEY (`ClientID`)
)ENGINE=InnoDB;
CREATE TABLE `profilePic` (
`ClientID` VARCHAR(100) NOT NULL,
PRIMARY KEY (`ClientID`),
CONSTRAINT `FK__user_details` FOREIGN KEY (`ClientID`) REFERENCES `user_details` (`ClientID`) ON UPDATE CASCADE ON DELETE CASCADE
)COLLATE='utf8mb4_unicode_ci' ENGINE=InnoDB;
The above failure is at the table level. A trickier one causing a 1215 error due to column-level collation mismatches can be seen in This answer.
Pulling the discussion up to more general cases ...
whether you are trying to establish a Foreign Key constraint on table creation or with ALTER TABLE
| ADD [CONSTRAINT [symbol]]
FOREIGN KEY [index_name] (index_col_name,...)
reference_definition
such as
ALTER TABLE `facility` ADD CONSTRAINT `fkZipcode`
FOREIGN KEY (`zipcode`) REFERENCES `allzips`(`zipcode`);
the following will apply.
From the MySQL manual page entitled Using FOREIGN KEY Constraints:
Corresponding columns in the foreign key and the referenced key must
have similar data types. 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 addition, the referenced (parent) table must have a left-most key available for fast lookup (verification). That parent key does not need to be PRIMARY or even UNIQUE. This concept is described in the 2nd chunk below. The first chunk alludes to a Helper index that will be created if necessary in the referencing (child) table if so necessary.
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.
InnoDB permits a foreign key to reference any column or group of
columns. However, in the referenced table, there must be an index
where the referenced columns are listed as the first columns in the
same order.
When trying to create a foreign key via HeidiSQL, you get a warning as soon as the selected column data types don't match. I added this warning to HeidiSQL's table designer due to the non-intuitive message from the server ("Cannot add foreign key constraint")
The selected foreign column do not match the source columns data type and unsigned flag. This will give you an error message when trying to save this change. Please compare yourself:

Why does MySQL Workbench automatically create multiple keys when creating relationships between tables?

Check out the image below. In the movie_custom table you'll see that when I added a 1:m relationship between plist_field and movie_custom, MySQL Workbench added keys for the attached tables of plist_type and plist_view_type in additional to the key I was expecting.
Why is that?
Can/should I remove them?
Or if I should keep them, how do I auto-insert the key values from the deeper tables when doing an insert into movie_custom and I know a key of plist_field?
If we execute this schema creation:
create table parent
( pid int auto_increment primary key,
theirName varchar(100) not null
);
drop table if exists child;
create table child
( cid int auto_increment primary key,
theirName varchar(100) not null,
pid int not null,
foreign key `fk_c2p` (pid) references parent(pid)
);
Examine what happened to the child:
mysql> show create table child \G;
CREATE TABLE `child` (
`cid` int(11) NOT NULL AUTO_INCREMENT,
`theirName` varchar(100) NOT NULL,
`pid` int(11) NOT NULL,
PRIMARY KEY (`cid`),
KEY `fk_c2p` (`pid`), -- ******************** AUTO created by mysql
CONSTRAINT `child_ibfk_1` FOREIGN KEY (`pid`) REFERENCES `parent` (`pid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
From the manual page Using FOREIGN KEY Constraints:
... index_name represents a foreign key ID. The index_name value is
ignored if there is already an explicitly defined index on the child
table that can support the foreign key. Otherwise, MySQL implicitly
creates a foreign key index that is named according to the following
rules:
If defined, the CONSTRAINT symbol value is used. Otherwise, the
FOREIGN KEY index_name value is used.
If neither a CONSTRAINT symbol or FOREIGN KEY index_name is defined,
the foreign key index name is generated using the name of the
referencing foreign key column.
So, back to your questions.
A. Why are they created? They are created because mysql creates them as specified above. They facilitate speedy reversal lookups. When a parent row is to be deleted, a fast non-table scan of children is mandated to allow or disallow the parent row removal. The auto-generated key (or one already satisfying it) is used for this purpose.
B. Should you delete them? No. Why not? Read A.
C. How do you "auto-insert the key values from the deeper tables": you acquire the id of the parent (anywhere in the hierarchy) ahead of time such as using LAST_INSERT_ID() or other program logic.

Duplicate entry error in 1 column of a composite key

I am trying to insert pseudo data into my db to get going, and in one particular table I have two columns which are FK's and PK's of the table; fk_product_manf_code and fk_content_id. To my understanding, these are considered composite keys in their current state.
So I add data to the table:
fk_product_manf_code fk_content_id
NOV-ABC123 1
I then want to associate another content_id to the same product_manf_code, so I perform the following:
INSERT INTO `mydb`.`package_contents`
(`fk_product_manf_code`, `fk_content_id`)
VALUES
('NOV-ABC123', 2);
However I'm greeted with the following error:
Error Code: 1062. Duplicate entry 'NOV-ABC123' for key 'fk_product_manf_code_UNIQUE'
I don't understand what's going, because I thought a composite key makes 2 columns unique? So why is it kicking up a fuss about just 1 column being unique?
Here is the table CREATE statement
CREATE TABLE `package_contents` (
`fk_product_manf_code` varchar(255) NOT NULL,
`fk_content_id` int(11) NOT NULL,
PRIMARY KEY (`fk_content_id`,`fk_product_manf_code`),
UNIQUE KEY `fk_content_id_UNIQUE` (`fk_content_id`),
UNIQUE KEY `fk_product_manf_code_UNIQUE` (`fk_product_manf_code`),
CONSTRAINT `content_id` FOREIGN KEY (`fk_content_id`) REFERENCES `contents` (`content_id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT `product_manf_code` FOREIGN KEY (`fk_product_manf_code`) REFERENCES `products` (`product_manf_code`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
So, you are learning why composite primary keys are a pain, especially for foreign key constraints. Not only are integer keys more efficient, but a single key is easier to work with.
I would suggest changing your table structure to be more like this:
CREATE TABLE package_contents (
package_contents_id int not null auto_increment primary key,
fk_product_manf_id int NOT NULL,
fk_content_id int(11) NOT NULL,
UNIQUE KEY (fk_content_id, fk_product_manf_id),
CONSTRAINT content_id FOREIGN KEY (fk_content_id)
REFERENCES contents(content_id) ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT product_manf_code FOREIGN KEY (fk_product_manf_id)
REFERENCES products(product_manf_id) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
Note that I changed the manufacturer code to an id as well. This should also reduce the size of the table, assuming that the "code" is longer than 4 bytes.
If you do this for all your tables, the database will be a bit more efficient, and you won't need superfluous unique constraints. The foreign key constraints should always be to primary keys (unless there is a very good reason for using a different unique key).

Can't add Foreign Key in MySQL with identical columns

I have two tables, each with a provider column:
CREATE TABLE `title` (
`provider` varchar(40) CHARACTER SET latin1 NOT NULL,
CREATE TABLE `notification` (
`provider` varchar(40) CHARACTER SET latin1 NOT NULL,
However, when I try and add a foreign key
ALTER TABLE notification ADD FOREIGN KEY (provider) REFERENCES title (provider)
I get the following obscure error:
Can't create table 'metadata.#sql-c91_345b' (errno: 150)
Both of the tables are empty. Why is this occurring and what do I need to do to fix this?
http://dev.mysql.com/doc/refman/5.0/en/innodb-foreign-key-constraints.html says:
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 think you should create any (unique, primary, or plain) index for title.provider before creating a foreign key pointing to it.
Run SHOW ENGINE INNODB STATUS\G and look at the "LATEST FOREIGN KEY ERROR" to see more details on the error.