mysql RDBMS, applying foreign key constraints in many tables - php

Hello friends I am working on a school database system based on php mysql. the basic structure is as below:
Table Class-Details of all classes. Primary Key Class ID
Table Student-Details of all students, Primary key studentID. Foreign Key ClassID
Table Semester-Details of all Semesters, key SemesterID
Table class–Semester. This table solves many to many relation, primary key- IDs of both class and semester. Foreign Key ClassID, SemesterID
Table Subject -Details of all Subjects, key SubjectID
Table class–Subject. This table solves many to many relation, primary key- IDs of both class and semester. Foreign Key ClassID, SubjectID
Table marks- consists of student ID, Subject ID, Semester ID, Marks Achieved.Foreign Key ClassID, SemesterID, SubjectID
I have also applied foreign keys in all the tables which are referring back to the parent table. I am looking to apply integrity in my database so that a student for a particular class will automatically be assigned to subjects of that particular class.
If we try to change the subjects of the student, database should throw an error that these subjects belong to the class for which student is a part of.
I am sure this can be done using foreign key constraints. However, I am bit naive to do so. A working example is highly appreciated
ENGINE = InnoDB
AUTO_INCREMENT = 53
DEFAULT CHARACTER SET = utf8;

Ok, I'll try to help. :-) First make sure you know the syntax completely by using the MySQL Manual for creating tables.
MySQL 5.1: CREATE TABLE
Look for the sections that look like this.
reference_definition:
REFERENCES tbl_name (index_col_name,...)
[MATCH FULL | MATCH PARTIAL | MATCH SIMPLE]
[ON DELETE reference_option] <----
[ON UPDATE reference_option] <----
reference_option:
RESTRICT | CASCADE | SET NULL | NO ACTION
Here is an example (...attept ...) from a child table of contact statistics that links to a contacts (people) parent table.
CREATE TABLE IF NOT EXISTS contactStats_tbl(
id INT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'Contact ID number.',
email VARCHAR(254) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL COMMENT 'E-mail address from contacts_tbl.',
subscribeTime TIMESTAMP DEFAULT '0000-00-00 00:00:00' COMMENT 'Time of subscription.',
unsubscribeTime TIMESTAMP DEFAULT '0000-00-00 00:00:00' COMMENT 'Time of unsubscription.',
totalMessages INT(4) NOT NULL COMMENT 'Number of messages sent.',
newsLetter ENUM('Y', 'N') CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT 'N' COMMENT 'Newsletter subscription.',
CONSTRAINT csconstr01 FOREIGN KEY (id, email) REFERENCES contacts_db.contacts_tbl(id, email) ON UPDATE CASCADE ON DELETE RESTRICT)
ENGINE=InnoDB DEFAULT CHARACTER SET = utf8 COMMENT 'Contact statistics table.';
Essentially, with table constraints you are focusing on a time when someone attempts to DELETE or UPDATE a record in a child table containing fields that point to a parent table (foreign keys, in this case). For all of your child tables, my advice would be to set the ON DELETE options to RESTRICT (the default). But, for ON UPDATE, child tables should probably CASCADE to keep them consistent with their parents (I have not researched referential integrity for a while, but I think that's how it goes! Dang that MS Access! Don't vote me down if I am wrong. Just comment and I'll fix my answer. :-)). The best thing to do would be to make sure you know how referential integrity applies to the situation at hand. Truthfully, I forget how the ON UPDATE bit works because I have not used it in a while. :-)
Now, as far as automatically inserting field values into a record (in a secondary table) based on actively inserting a record into some other table (primary table), make sure that you are not in need of a trigger.
MySQL 5.1: CREATE TRIGGER
This should get you going. I tried! :-)
Anthony

Related

Can't create a table with ForeignKey in migrations file using Codeigniter 4 [duplicate]

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

How do I display the name of a table on SQL

First of all, I'm from Spain so I'm sorry if I made some mistakes writing. So, I have two problems. It will be better if I give context before. I am not even junior, still learning code, and I thought that it will be a good proyect to create a web page where you can add ingredients, foods with that ingredients, etc. So I decided to start learning PHP and SQL. Now I'm trying to create a database, starting with some ingredients and two kinds of rices. My 1st problem is that I don't know if I need to create a data base for that. The second and main one is that I don't have any idea about how to get this working as I want.
See, First of all I created the table for ingredients´
CREATE TABLE ingredientes(
id int(255) auto_increment not null,
ingrediente varchar(255) not null,
CONSTRAINT pk_ingredientes PRIMARY KEY(id) )ENGINE=InnoDb;
Sorry 'cause it's on spanish :/, but nothing to hard to understand.
So I add some ingredients.
Here the pic showing them
After that I created two tables, and add ingredients to them.
CREATE TABLE arroz_con_pollo(
id int(255) auto_increment not null,
ingrediente int(255) not null,
CONSTRAINT pk_arroz_con_pollo PRIMARY KEY(id),
CONSTRAINT fk_pollo_ingredientes FOREIGN KEY(ingrediente) REFERENCES ingredientes(id) )ENGINE=InnoDb;
CREATE TABLE arroz_cubana(
id int(255) auto_increment not null,
ingrediente int(255) not null,
CONSTRAINT pk_arroz_cubana PRIMARY KEY(id),
CONSTRAINT fk_cubana_ingredientes FOREIGN KEY(ingrediente) REFERENCES ingredientes(id))ENGINE=InnoDb;
Here the picture showing the ID's.
Here
So now I spend a lot of time researching and find out that I can show the names by using this command
SELECT a.id,i.ingrediente
FROM ingredientes i, arroz_cubana a
WHERE i.id = a.id;
And have something like this
At this point, everything is, more or less, working. My issue came when I want to create a data base that keep all the names (arroz con pollo, arroz cubana...) in an only table named as 'rices' to be able to choose a name, and automatically have the ingredients there, without any complication for the user. But, I literally have no idea. I've been coding for hours without any victory on that. And I haven't see anything similar on the web so, if someone tell me how to fix that issue or how to make that idea of a web to keep ingredients and foods, I'll be very greatful.
Your data structure is messed up. SQL is not designed to have a separate table for each ingredient. Instead, you want two other tables.
The first is for dishes:
CREATE TABLE dishes (
dish_id int auto_increment not null,
name varchar(255)
);
You would then insert appropriate rows into this:
INSERT INTO dishes (name)
VALUES ('arroz_on_pollo');
Then you have another table for the ingredients:
CREATE TABLE dishes_ingredients (
dish_ingredient_id int auto_increment primary key,
dish_id int not null
ingredient_id int not null,
CONSTRAINT fk_dish_ingredientes_dish FOREIGN KEY(dish_id) REFERENCES dishes(dish_id)
CONSTRAINT fk_dish_ingredientes_dish FOREIGN KEY(ingredient_id) REFERENCES ingredientes(ingredient_id)
);
Voila! New dishes are just rows in a table, so you can get the names using a SELECT.
Notes on structure:
int(255) really makes no sense. Just use int. The number in parentheses is a width for the value when printing it and 255 is a ridiculous width.
I am a fan of naming primary keys with the table name. That way, the primary key and foreign key typically have the same name.
You should not have a table per dish. Create one table "dish", that includes a column "name". Each row represents a dish. Then create a supporting table where you list the (multiple) ingredients for each dish. Look around for a tutorial on databases, this topic is too large to explain in a stackoverflow question (or several).
And so you do not need to be able to list the table names, the way you were considering. (Which is not something SQL supports directly; different databases provide non-standard ways to do it, but as explained you do not actually need such a feature.)

SQLSTATE[HY000]: General error: 1215 Cannot add foreign key constraint laravel 5.6.5 [duplicate]

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

Error when run the migration command [duplicate]

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

INNODB cascade on delete and update

I'm trying to create some tables in a mysql db to handle customers, assign them to groups and give customers within these groups unique promotion codes/coupons.
there are 3 parent(?) tables - customers, groups, promotions
then I have table - customerGroups to assign each customer_id to many group_id's
also I have - customerPromotions to assign each customer_id to many promotion_id's
I know I need to use cascade on delete and update so that when I delete a customer, promotion or group the data is also removed from the child tables. I put together some php to create the tables easily http://pastebin.com/gxhW1PGL
I've been trying to read up on cascade, foreign key references but I think I learn better by trying to do things then learning why they work. Can anyone please give me their input on what I should do to these tables to have them function correctly.
I would like to have the database and tables set up correctly before I start with queries or anything further so any advice would be great.
You seem to want just a little guidance. So I'll try to be brief.
$sql = "CREATE TABLE customerGroups (
customer_id int(11) NOT NULL,
group_id int(11) NOT NULL,
PRIMARY KEY (customer_id, group_id),
CONSTRAINT customers_customergroups_fk
FOREIGN KEY (customer_id)
REFERENCES customers (customer_id)
ON DELETE CASCADE,
CONSTRAINT groups_customergroups_fk
FOREIGN KEY (group_id)
REFERENCES groups (group_id)
ON DELETE CASCADE
)ENGINE = INNODB;";
You only need id numbers when identity is hard to nail down. When you're dealing with people, identity is hard to nail down. There are lots of people named "John Smith".
But you're dealing with two things that have already been identified. (And identified with id numbers, of all things.)
Cascading deletes makes sense. It's relatively rare to cascade updates on id numbers; they're presumed to never change. (The main reason Oracle DBAs insist that primary keys must always be ID numbers, and that they must never change is because Oracle can't cascade updates.) If, later, some id numbers need to change for whatever reason, you can alter the table to include ON UPDATE CASCADE.
$sql = "CREATE TABLE groups
(
group_id int(11) NOT NULL AUTO_INCREMENT,
group_title varchar(50) NOT NULL UNIQUE,
group_desc varchar(140),
PRIMARY KEY (group_id)
)ENGINE = INNODB;";
Note the additional unique constraint on group_title. You don't want to allow anything like this (below) in your database.
group_id group_title
--
1 First group
2 First group
3 First group
...
9384 First group
You'll want to carry those kinds of changes through all your tables. (Except, perhaps, your table of customers.)

Categories