Multiple Primary/Foreign Keys - mysql

I'm going to be honest, I'm a bit hazy on how primary and foreign keys work. I was told to setup my database by someone on here so that I had 7 tables, one for organizations, one for categories, services, and cultures, and three cross reference tables between organization on one hand, and categories, services and cultures on the other.
Take the org_culture_xref table, for instance. I have two columns, one is org_id, which is the same as the org_id column (primary key) of the organization table. The other is cult_id, which is the same as the cult_id column (primary key) of the culture table.
I believe both of the columns of the org_culture_xref table are primary and foreign keys. However, this doesn't seem to allow me to have multiple values for both of these columns. I want to be able to have several relationships between organizations and cultures - as in every organization can be associated with multiple cultures and every culture can be associated with multiple organizations.
How do I ensure that I can have multiple values for both columns?

What you're talking about is a Many-To-Many relationship. You're on the right path using a cross-reference table.
It's good to review how foreign and primary keys work; there can only be one primary key per table, but there can be multiple foreign keys. However, note that a primary key doesn't have to be limited to one column; you can have a primary key that spans two, three, or more columns.
Your solution here is to have two foreign key, one for each column/table relationship, and one primary key that spans across both tables.
Here's an example of a table I used at one time, which links cities and counties in a many-to-many relationship.
mysql> show create table xref_cities_counties\G
*************************** 1. row ***************************
Table: xref_cities_counties
Create Table: CREATE TABLE `xref_cities_counties` (
`city_id` int(10) unsigned NOT NULL,
`county_id` tinyint(3) unsigned NOT NULL,
PRIMARY KEY (`city_id`,`county_id`),
KEY `city_id` (`city_id`),
KEY `county_id` (`county_id`),
CONSTRAINT `fk_xrefcitiescounties_cityid` FOREIGN KEY (`city_id`) REFERENCES `florida_cities` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `fk_xrefcitiescounties_countyid` FOREIGN KEY (`county_id`) REFERENCES `florida_counties` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=latin1
1 row in set (0.00 sec)
mysql>
mysql>
mysql> describe xref_cities_counties;
+-----------+---------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------+---------------------+------+-----+---------+-------+
| city_id | int(10) unsigned | NO | PRI | | |
| county_id | tinyint(3) unsigned | NO | PRI | | |
+-----------+---------------------+------+-----+---------+-------+
2 rows in set (0.00 sec)
mysql>
I'd suggest some extra reading on the topic. It seems like you're on a good start.

The primary key for your cross ref table will be both of the columns, meaning that the combination of two ids must be unique but you can have repeats of individiual ids in either column.
Here is a statement to create such a table:
CREATE TABLE `x` (
`a_id` varchar(6) NOT NULL default '',
`b_id` varchar(6) NOT NULL default '',
PRIMARY KEY (`a_id`,`b_id`)
)
The issue itself and the cross ref table approach to many-to-many relationships applies to most (if not all) relational databases, but since I haven't used mysql in around 10 years I got that code from here, which seems to have a detailed discussion of the topic with mysql specific code.

Each column of org_culture_xref is a foreign key: org_id is a foreign key to organization, and cult_id is a foreign key to culture. The two of them together are the primary key of org_culture_xref.
So, something along these lines:
CREATE TABLE org_culture_xref
(
org_id NUMERIC(10) NOT NULL,
cult_id NUMERIC(10) NOT NULL,
PRIMARY KEY (org_id, cult_id),
FOREIGN KEY (org_id) REFERENCES organization (org_id),
FOREIGN KEY (cult_id) REFERENCES culture (cult_id)
);

Related

Indexed item from 2 tables into one column

I want to restrict one column in `orders` MySQL table to primary key from **2 different tables**.
Example:
I have one table orders
|order_id|item_1 |item_2 |price|
|1 |service_id1|product_id1|10.00|
|2 |product_id1|service_id1|10.00|
Columns item_1 and item_2 are basic indexes and I want to restrict each of them to following tables:
services
|service_id |name |price|
|service_id1|service1|5.00 |
|service_id2|service2|5.00 |
products
|product_id |name |price|
|product_id1|product1|5.00 |
|product_id2|product2|5.00 |
Basically i just want to insert data from both services and products into one column: orders.item_1 or orders.item_2. Is it possible? I added both name restrictions in phpmyadmin but it doesn't work like it suppose to work, generating error 1452. Maybe I'm overthinking and the solution is easier than I think or I just want too much from mysql.
This is only a foreign key constraint
Joining both in a single column makes no sense, but is doable
what you essentially have is a bridge taböe, to join different ids from different tables. As the ids are indexed this is ver fast, especially when you are looking for few items .
in the sample you need to have in both tables a 1 to add to orders a 1 as reference, and so you always must have products and services in sync with each other
CREATE tABLE products (product_id bigint Primary KEY auto_increment, name VARCHAR(255),price DECIMAL (10,2))
CREATE tABLE services (sercvice_id bigint Primary KEY auto_increment, name VARCHAR(255),price DECIMAL (10,2))
CREATE TABLe orders (order_id BIGINT AUTO_INCREMENT PRIMARY KEY
,item_1 BIGINT
, item_2 BIGINT
, price DECIMAL(10,2)
,
CONSTRAINT FK_OrdersProducts FOREIGN KEY (item_1)
REFERENCES products(product_id),
CONSTRAINT FK_OrdersServices FOREIGN KEY (item_2)
REFERENCES services(sercvice_id)
, INDEX (item_1,item_2)
)
db<>fiddle here
CREATE tABLE products (product_id bigint Primary KEY auto_increment, name VARCHAR(255),price DECIMAL (10,2))
CREATE tABLE services (sercvice_id bigint Primary KEY auto_increment, name VARCHAR(255),price DECIMAL (10,2))
CREATE TABLe orders (order_id BIGINT AUTO_INCREMENT PRIMARY KEY
,item_1 BIGINT
, price DECIMAL(10,2)
,
CONSTRAINT FK_OrdersProducts FOREIGN KEY (item_1)
REFERENCES products(product_id),
CONSTRAINT FK_OrdersServices FOREIGN KEY (item_1)
REFERENCES services(sercvice_id)
)
db<>fiddle here

ERROR: Error 1452: Cannot add or update a child row: a foreign key constraint fails (`jmr17e`.`employee`, [duplicate]

I'm having some problems creating a foreign key to an existing table in a MySQL database.
I have the table exp:
+-------------+------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------------+------------------+------+-----+---------+-------+
| EID | varchar(45) | NO | PRI | NULL | |
| Comment | text | YES | | NULL | |
| Initials | varchar(255) | NO | | NULL | |
| ExpDate | date | NO | | NULL | |
| InsertDate | date | NO | | NULL | |
| inserted_by | int(11) unsigned | YES | MUL | NULL | |
+-------------+------------------+------+-----+---------+-------+
and I wan't to create a new table called sample_df referencing this, using the following:
CREATE TABLE sample_df (
df_id mediumint(5) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
sample_type mediumint(5) UNSIGNED NOT NULL,
df_10 boolean NOT NULL,
df_100 boolean NOT NULL,
df_1000 boolean NOT NULL,
df_above_1000 boolean NOT NULL,
target int(11) UNSIGNED NOT NULL,
assay mediumint(5) UNSIGNED ZEROFILL NOT NULL,
insert_date timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
inserted_by int(11) UNSIGNED NOT NULL,
initials varchar(255),
experiment varchar(45),
CONSTRAINT FOREIGN KEY (inserted_by) REFERENCES user (iduser),
CONSTRAINT FOREIGN KEY (target) REFERENCES protein (PID),
CONSTRAINT FOREIGN KEY (sample_type) REFERENCES sample_type (ID),
CONSTRAINT FOREIGN KEY (assay) REFERENCES assays (AID),
CONSTRAINT FOREIGN KEY (experiment) REFERENCES exp (EID)
);
But I get the error:
ERROR 1215 (HY000): Cannot add foreign key constraint
To get some more information, I did:
SHOW ENGINE INNODB STATUS\G
From which I got:
FOREIGN KEY (experiment) REFERENCES exp (EID)
):
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.
To me, the column types seem to match, since they are both varchar(45). (I also tried setting the experiment column to not null, but this didn't fix it). So I guess the problem must be that
Cannot find an index in the referenced table where the referenced columns appear as the first columns.
But I'm not quite sure what this means, or how to check/fix it. Does anyone have any suggestions? And what is meant by first columns?
Just throwing this into the mix of possible causes, I ran into this when the referencing table column had the same "type" but did not have the same signing.
In my case, the referenced table colum was TINYINT UNSIGNED and my referencing table column was TINYINT SIGNED. Aligning both columns solved the issue.
This error can also occur, if the references table and the current table don't have the same character set.
According to http://dev.mysql.com/doc/refman/5.5/en/create-table-foreign-keys.html
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.
InnoDB permits a foreign key to reference any index 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.
So if the index in referenced table is exist and it is consists from several columns, and desired column is not first, the error shall be occurred.
The cause of our error was due to violation of following rule:
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.
As mentioned #Anton, this could be because of the different data type.
In my case I had primary key BIGINT(20) and tried to set foreight key with INT(10)
Mine was a collation issue between the referenced table and the to be created table so I had to explicitly set the collation type of the key I was referencing.
First I ran a query at referenced table to get its collation type
show table STATUS like '<table_name_here>';
Then I copied the collation type and explicitly stated employee_id's collation type at the creation query. In my case it was utf8_general_ci
CREATE TABLE dbo.sample_db
(
id INT PRIMARY KEY AUTO_INCREMENT,
event_id INT SIGNED NOT NULL,
employee_id varchar(45) COLLATE utf8_general_ci NOT NULL,
event_date_time DATETIME,
CONSTRAINT sample_db_event_event_id_fk FOREIGN KEY (event_id) REFERENCES event (event_id),
CONSTRAINT sample_db_employee_employee_id_fk FOREIGN KEY (employee_id) REFERENCES employee (employee_id)
);
In my case, it turned out the referenced column wasn't declared primary or unique.
https://stackoverflow.com/a/18435114/1763217
For me it was just the charset and collation of the DB. I changed to utf8_unicode_ci and works
In my case, it was an incompatibility with ENGINE and COLLATE, once i added ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci it worked
CREATE TABLE `some_table` (
`id` varchar(36) NOT NULL,
`col_id` varchar(36) NOT NULL,
PRIMARY KEY (`id`),
CONSTRAINT `FK_some_table_cols_col_id` FOREIGN KEY (`col_id`) REFERENCES `ref_table` (`id`) ON DELETE CASCADE,
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
The exact order of the primary key also needs to match with no extra columns in between.
I had a primary key setup where the column order actually matches, but the problem was the primary key had an extra column in it that is not part of the foreign key of the referencing table
e.g.) table 2, column (a, b, c) -> table 1, column (a, b, d, c) -- THIS FAILS
I had to reorder the primary key columns so that not only they're ordered the same way, but have no extra columns in the middle:
e.g.) table 2, column (a, b, c) -> table 1, column (a, b, c, d) -- THIS SUCCEEDS
I had this error as well. None of the answers pertained to me. In my case, my GUI automatically creates a table with a primary unique identifier as "unassigned". This fails when I try and create a foreign key and gives me the exact same error. My primary key needs to be assigned.
If you write the SQL itself like so id int unique auto_increment then you don't have this issue but for some reason my GUI does this instead id int unassigned unique auto_increment.
Hope this helps someone else down the road.
In my case was created using integer for the id, and the referencing table was creating by default a foreign key using bigint.
This caused a big nightmare in my Rails app as the migration failed but the fields were actually created in DB, so they showed up in the DB but not in the schema of the Rails app.
Referencing the same column more than once in the same constraint also produces this Cannot find an index in the referenced table error, but can be difficult to spot on large tables. Split up the constraints and it will work as expected.
In some cases, I had to make the referenced field unique on top of defining it as the primary key.
But I found that not defining it as unique doesn't create a problem in every case. I have not been able to figure out the scenarios though. Probably something to do with nullable definition.
Just to throw another solution in the mix. I had on delete set to set null but the field that i was putting the foreign key on was NOT nullable so making it nullable allowed the foreign key to be created.
As others have said the following things can be an issue
Field Length - INT -> BIGINT, VARCHAR(20) -> VARCHAR(40)
Unsigned - UNSIGNED -> Signed
Mixed Collations
And just to add to this , I've had the same issue today
Both fields were int of same length etc, however, one was unsigned and this was enough to break it.
Both needed to be declared as unsigned
I had the same problem with writing this piece of code in the OnModelCreating method
My problem was completely solved and my tables and migrations were created without errors. Please try it
var cascadeFKs = modelBuilder.Model.GetEntityTypes()
.SelectMany(t => t.GetForeignKeys())
.Where(fk => !fk.IsOwnership && fk.DeleteBehavior == DeleteBehavior.Cascade);
foreach (var fk in cascadeFKs)
fk.DeleteBehavior = DeleteBehavior.Restrict;
It is mostly because the old table you are referring to does not have the suitable data type / collation / engine with the new table. The way to detect the difference is dumping that old table out and see how the database collect the information to have the dump script
mysqldump -uroot -p -h127.0.0.1 your_database your_old_table > dump_table.sql
It will give you enough information for you to compare
create table your_old_table
(
`id` varchar(32) not null,
) Engine = InnoDB DEFAULT CHARSET=utf8mb3;
This only works if you have the permission to dump your table scheme
I spent hours trying to get this to work. It turned out I had an older version of Heidi, 11.0.0.5919 which was not displaying the UNSIGNED attribute in the create table statement (Heidi bug), which I had used to copy from. Couldn't see it in the table design view either.
So the original table had an UNSIGNED attribute, but my foreign key didn't. The solution was upgrading Heidi, and adding the UNSIGNED attribute in the create table .
CREATE TABLE `extension` (
`ExtensionId` INT NOT NULL,
`AccountId` INT NOT NULL,
PRIMARY KEY (`ExtensionId`) USING BTREE,
INDEX `AccountId` (`AccountId`) USING BTREE,
CONSTRAINT `AccountId` FOREIGN KEY (`AccountId`) REFERENCES `accounts` (`AccountId`) ON UPDATE NO ACTION ON DELETE NO ACTION,
)
COLLATE='utf8mb4_0900_ai_ci'
ENGINE=InnoDB
;
Change to:
`AccountId` INT UNSIGNED NOT NULL,
If Data type is same, Probably error is due to different Charset and Collation, try altering column as referenced column's Character set and Collate with a query something like this,
ALTER TABLE table_name MODIFY COLUMN
column_name VARCHAR(255) CHARACTER SET utf8 COLLATE utf8_general_ci;
and then run the query for foreign key..
(alter charset of a table and database didn't work for me on incompatible error, until I alter specific column like my above suggestion)
In my case I referred directly to a PRIMARY KEY and got the error shown above. After adding a "normal" index additionally to my primary key it worked:
ALTER TABLE `TableName` ADD INDEX `id` (`id`);
Now it looks like this:
When I try to drop the INDEX id again I get following error:
(1553): Cannot drop index 'id': needed in a foreign key constraint.
EDIT:
This is not a new question - I just want to show the way i solved this problem for me and what kind of problems may occur.

Mysql create table with two foreign keys referencing primary key

I have two mysql tables. The first one is created using the following code:
create table project(
project_id int not null auto_increment,
project_name varchar(30)
primary key(project_id));
The second table:
create table matches(
match_id int not null auto_increment,
match_name varchar(30),
project_id int(4) foreign key (project_id) references projects(project_id));
Both these commands works fine. I want to add the project_name column from the first table to the second table. I tried using
alter table projects drop primary key, add primary key(project_id, project_name);
and then
alter table matches add column project_name varchar(30), add foreign key (project_name) references projects(project_name);
But got the following error:
ERROR 1005 (HY000): Can't create table 'matches.#sql-55e_311' (errno: 150)
How do i include both the columns from the first table into the second table.
The current structure of my second table is as follows:
+------------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+-------------+------+-----+---------+----------------+
| match_id | int(11) | NO | PRI | NULL | auto_increment |
| match_name | varchar(30) | YES | | NULL | |
| project_id | int(4) | NO | MUL | NULL | |
+------------+-------------+------+-----+---------+----------------+
I want to add the project_name as the fourth column in my second table.
To use a compound Primary Key as Foreign Key, you'll have to add the
same number of columns (that compose the PK) with same datatypes to
the child table and then use the combination of these columns in the
FOREIGN KEY definition.
see related post here https://stackoverflow.com/a/10566463/4904726
so try this way
alter table matches add foreign key (project_id, project_name) references projects(project_id, project_name);
Do you understand what a FK constraint says? It says a list of values for some columns in a table must appear as a list of values for some columns forming a (declared) PK or UNIQUE NOT NULL in the referenced table. So what you are writing doesn't make sense. If you wanted a PK (project_id, project_name) then that should also be the form of your FK.
But (project_id, project_name) is not two 1-column PKs, it is one 2-column PK, and it is probably not what you want since presumably in projects it isn't just pairs that are unique it is each column. Presumably you want two 1-column PKs and two one-column FKs, one referencing each PK.
If projects project_id was NOT NULL you could write:
alter table projects add primary key(project_name);
alter table matches add column project_name varchar(30),
add foreign key (project_name) references projects(project_name);
But if project_name can be NULL in projects then you cannot make it a PK and you cannot sensibly have a FK to it. You can make it UNIQUE. Unfortunately MySQL lets you write such a FK declaration to a non-NULL UNIQUE column while it also tells you not to do it:
The handling of foreign key references to non-unique keys or keys that contain NULL values is not well defined for operations such as UPDATE or DELETE CASCADE. You are advised to use foreign keys that reference only keys that are both UNIQUE (or PRIMARY) and NOT NULL.
So if you want projects project_name to be nullable then should declare it UNIQUE but you should enforce the logical matches project_name match with a trigger.

Primary key or foreign key for table with identical unique columns

See indicative schema below.
Table 2 contains the different formats of films. E.g. 2D, 3D, 4D etc.
It has the formats as the columns and the end column is the film ID number from table 1.
As my film ID column in table 1 is my primary key for table 1, It lead my to believe that the film ID column in table 2 is a foreign key. However this leaves my without a primary key in table 2.
Is it best practice to leave table 2 without a primary key in this instance, or set both film IDs as primary keys for both tables, or should I create another column in table 2 allowing for a "film format ID" which would be my table 2 primary key?
For visual reference:
table 1 table 2
-------|------- -------|-------|-------|-------
Film |film ID Film ID| 3D | 4D | 2D
^primary key ^foreign key
It seems to me that many films come in multiple formats, so it would be mistake to make filmid a PK in the second table. Further the design is not normalized and highly flawed. You should have a third table of Film types that is a look up table. Then the second table should contain only the filmid and the filmtypeid and you can create a Primary key on the combination of both fields. THis is called a junction table.
Table 2 is like a child to your table 1, been the parent. This is because table 1 can exist without table 2, but table 2 cannot without table 1 because it relies on the film id primary key to create itself a set of information (you cant have a 2d or 3d formats of a non existent film).
To answer your question about making film id primary in both tables; no don't do this. The primary key uniquely identifies a column of data in a table that can be referenced with a foreign key in another table. If it was also primary key in table 2 it wouldn't refer to table 1's data because there is no relationship made.
If i understood your needs, you can use those two tables:
CREATE TABLE `film` (
`id` int(11) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
CREATE TABLE `film_format` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`film_id` int(11) DEFAULT NULL,
`format` enum('2D','3D','4D') CHARACTER SET latin1 DEFAULT '2D',
PRIMARY KEY (`id`),
KEY `fk` (`film_id`),
CONSTRAINT `fk` FOREIGN KEY (`film_id`) REFERENCES `film` (`id`) ON DELETE SET NULL ON UPDATE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8
You are having trouble because your table design violates first normal form. Each unique combination of [film,format] should be contained in its own row in table 2.
May I suggest this alternative:
Table 1
A list of films, with a primary key of FilmID.
Table 2
A list of formats supported by films.
Columns: FilmID (FK), FormatID (FK)
Primary key: Either a compound key of FilmID+FormatID, or a surrogate key
Table 3
A list of potential film formats
Columns: FormatID, Format Description (2D, 3D, etc.)
Primary key: FormatID
You don't need a primary key on table 2, just an unique index.
But if you want, you can use an artificial key like an identity field. In this instance, at 1x1 relationship, i think thas's unnecessary.

MySQL cannot create foreign key constraint

I'm having some problems creating a foreign key to an existing table in a MySQL database.
I have the table exp:
+-------------+------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------------+------------------+------+-----+---------+-------+
| EID | varchar(45) | NO | PRI | NULL | |
| Comment | text | YES | | NULL | |
| Initials | varchar(255) | NO | | NULL | |
| ExpDate | date | NO | | NULL | |
| InsertDate | date | NO | | NULL | |
| inserted_by | int(11) unsigned | YES | MUL | NULL | |
+-------------+------------------+------+-----+---------+-------+
and I wan't to create a new table called sample_df referencing this, using the following:
CREATE TABLE sample_df (
df_id mediumint(5) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
sample_type mediumint(5) UNSIGNED NOT NULL,
df_10 boolean NOT NULL,
df_100 boolean NOT NULL,
df_1000 boolean NOT NULL,
df_above_1000 boolean NOT NULL,
target int(11) UNSIGNED NOT NULL,
assay mediumint(5) UNSIGNED ZEROFILL NOT NULL,
insert_date timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
inserted_by int(11) UNSIGNED NOT NULL,
initials varchar(255),
experiment varchar(45),
CONSTRAINT FOREIGN KEY (inserted_by) REFERENCES user (iduser),
CONSTRAINT FOREIGN KEY (target) REFERENCES protein (PID),
CONSTRAINT FOREIGN KEY (sample_type) REFERENCES sample_type (ID),
CONSTRAINT FOREIGN KEY (assay) REFERENCES assays (AID),
CONSTRAINT FOREIGN KEY (experiment) REFERENCES exp (EID)
);
But I get the error:
ERROR 1215 (HY000): Cannot add foreign key constraint
To get some more information, I did:
SHOW ENGINE INNODB STATUS\G
From which I got:
FOREIGN KEY (experiment) REFERENCES exp (EID)
):
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.
To me, the column types seem to match, since they are both varchar(45). (I also tried setting the experiment column to not null, but this didn't fix it). So I guess the problem must be that
Cannot find an index in the referenced table where the referenced columns appear as the first columns.
But I'm not quite sure what this means, or how to check/fix it. Does anyone have any suggestions? And what is meant by first columns?
Just throwing this into the mix of possible causes, I ran into this when the referencing table column had the same "type" but did not have the same signing.
In my case, the referenced table colum was TINYINT UNSIGNED and my referencing table column was TINYINT SIGNED. Aligning both columns solved the issue.
This error can also occur, if the references table and the current table don't have the same character set.
According to http://dev.mysql.com/doc/refman/5.5/en/create-table-foreign-keys.html
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.
InnoDB permits a foreign key to reference any index 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.
So if the index in referenced table is exist and it is consists from several columns, and desired column is not first, the error shall be occurred.
The cause of our error was due to violation of following rule:
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.
As mentioned #Anton, this could be because of the different data type.
In my case I had primary key BIGINT(20) and tried to set foreight key with INT(10)
Mine was a collation issue between the referenced table and the to be created table so I had to explicitly set the collation type of the key I was referencing.
First I ran a query at referenced table to get its collation type
show table STATUS like '<table_name_here>';
Then I copied the collation type and explicitly stated employee_id's collation type at the creation query. In my case it was utf8_general_ci
CREATE TABLE dbo.sample_db
(
id INT PRIMARY KEY AUTO_INCREMENT,
event_id INT SIGNED NOT NULL,
employee_id varchar(45) COLLATE utf8_general_ci NOT NULL,
event_date_time DATETIME,
CONSTRAINT sample_db_event_event_id_fk FOREIGN KEY (event_id) REFERENCES event (event_id),
CONSTRAINT sample_db_employee_employee_id_fk FOREIGN KEY (employee_id) REFERENCES employee (employee_id)
);
In my case, it turned out the referenced column wasn't declared primary or unique.
https://stackoverflow.com/a/18435114/1763217
For me it was just the charset and collation of the DB. I changed to utf8_unicode_ci and works
In my case, it was an incompatibility with ENGINE and COLLATE, once i added ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci it worked
CREATE TABLE `some_table` (
`id` varchar(36) NOT NULL,
`col_id` varchar(36) NOT NULL,
PRIMARY KEY (`id`),
CONSTRAINT `FK_some_table_cols_col_id` FOREIGN KEY (`col_id`) REFERENCES `ref_table` (`id`) ON DELETE CASCADE,
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
The exact order of the primary key also needs to match with no extra columns in between.
I had a primary key setup where the column order actually matches, but the problem was the primary key had an extra column in it that is not part of the foreign key of the referencing table
e.g.) table 2, column (a, b, c) -> table 1, column (a, b, d, c) -- THIS FAILS
I had to reorder the primary key columns so that not only they're ordered the same way, but have no extra columns in the middle:
e.g.) table 2, column (a, b, c) -> table 1, column (a, b, c, d) -- THIS SUCCEEDS
I had this error as well. None of the answers pertained to me. In my case, my GUI automatically creates a table with a primary unique identifier as "unassigned". This fails when I try and create a foreign key and gives me the exact same error. My primary key needs to be assigned.
If you write the SQL itself like so id int unique auto_increment then you don't have this issue but for some reason my GUI does this instead id int unassigned unique auto_increment.
Hope this helps someone else down the road.
In my case was created using integer for the id, and the referencing table was creating by default a foreign key using bigint.
This caused a big nightmare in my Rails app as the migration failed but the fields were actually created in DB, so they showed up in the DB but not in the schema of the Rails app.
Referencing the same column more than once in the same constraint also produces this Cannot find an index in the referenced table error, but can be difficult to spot on large tables. Split up the constraints and it will work as expected.
In some cases, I had to make the referenced field unique on top of defining it as the primary key.
But I found that not defining it as unique doesn't create a problem in every case. I have not been able to figure out the scenarios though. Probably something to do with nullable definition.
Just to throw another solution in the mix. I had on delete set to set null but the field that i was putting the foreign key on was NOT nullable so making it nullable allowed the foreign key to be created.
As others have said the following things can be an issue
Field Length - INT -> BIGINT, VARCHAR(20) -> VARCHAR(40)
Unsigned - UNSIGNED -> Signed
Mixed Collations
And just to add to this , I've had the same issue today
Both fields were int of same length etc, however, one was unsigned and this was enough to break it.
Both needed to be declared as unsigned
I had the same problem with writing this piece of code in the OnModelCreating method
My problem was completely solved and my tables and migrations were created without errors. Please try it
var cascadeFKs = modelBuilder.Model.GetEntityTypes()
.SelectMany(t => t.GetForeignKeys())
.Where(fk => !fk.IsOwnership && fk.DeleteBehavior == DeleteBehavior.Cascade);
foreach (var fk in cascadeFKs)
fk.DeleteBehavior = DeleteBehavior.Restrict;
It is mostly because the old table you are referring to does not have the suitable data type / collation / engine with the new table. The way to detect the difference is dumping that old table out and see how the database collect the information to have the dump script
mysqldump -uroot -p -h127.0.0.1 your_database your_old_table > dump_table.sql
It will give you enough information for you to compare
create table your_old_table
(
`id` varchar(32) not null,
) Engine = InnoDB DEFAULT CHARSET=utf8mb3;
This only works if you have the permission to dump your table scheme
I spent hours trying to get this to work. It turned out I had an older version of Heidi, 11.0.0.5919 which was not displaying the UNSIGNED attribute in the create table statement (Heidi bug), which I had used to copy from. Couldn't see it in the table design view either.
So the original table had an UNSIGNED attribute, but my foreign key didn't. The solution was upgrading Heidi, and adding the UNSIGNED attribute in the create table .
CREATE TABLE `extension` (
`ExtensionId` INT NOT NULL,
`AccountId` INT NOT NULL,
PRIMARY KEY (`ExtensionId`) USING BTREE,
INDEX `AccountId` (`AccountId`) USING BTREE,
CONSTRAINT `AccountId` FOREIGN KEY (`AccountId`) REFERENCES `accounts` (`AccountId`) ON UPDATE NO ACTION ON DELETE NO ACTION,
)
COLLATE='utf8mb4_0900_ai_ci'
ENGINE=InnoDB
;
Change to:
`AccountId` INT UNSIGNED NOT NULL,
If Data type is same, Probably error is due to different Charset and Collation, try altering column as referenced column's Character set and Collate with a query something like this,
ALTER TABLE table_name MODIFY COLUMN
column_name VARCHAR(255) CHARACTER SET utf8 COLLATE utf8_general_ci;
and then run the query for foreign key..
(alter charset of a table and database didn't work for me on incompatible error, until I alter specific column like my above suggestion)
In my case I referred directly to a PRIMARY KEY and got the error shown above. After adding a "normal" index additionally to my primary key it worked:
ALTER TABLE `TableName` ADD INDEX `id` (`id`);
Now it looks like this:
When I try to drop the INDEX id again I get following error:
(1553): Cannot drop index 'id': needed in a foreign key constraint.
EDIT:
This is not a new question - I just want to show the way i solved this problem for me and what kind of problems may occur.