MySQL InnoDB Foreign Key Problems - mysql

I have the following tables and I am trying to run them in MySQL but I keep getting an errno 150. Just not sure why, but MySQL cannot seem to create the foreign key constraint. I have already looked at the rules for setting FKs for InnoDB and everything seems ok. Could someone please lend me another set of eyes and expertise?
-- Table publication_type (parent table)
CREATE TABLE publication_type (
id int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
publication_type varchar(55) NOT NULL,
tstamp timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT publication_type_pk PRIMARY KEY (id)
)ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;
-- Table publication (child table)
CREATE TABLE publication (
id int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
authors varchar(255) NOT NULL,
publication_title varchar(100) NOT NULL,
publication_type_id int(11) UNSIGNED NOT NULL,
user_id int(11) UNSIGNED NOT NULL,
CONSTRAINT publication_pk PRIMARY KEY (id),
CONSTRAINT publication_type_fk FOREIGN KEY (publication_type_id) REFERENCES publication_type(id) ON DELETE SET NULL ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;

The types do not match:
publication_type.id is of type int UNSIGNED
publication.publication_type_id is of type int
See also the docs: http://dev.mysql.com/doc/refman/5.1/en/create-table-foreign-keys.html, specifically:
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.
emphasis mine.

Related

Error when creating foreign key of type CHAR with mysql workbench: Error 1005: Can't create table (errno: 150)

I have defined the following 2 tables:
record_status
SHOW CREATE TABLE record_status
CREATE TABLE `record_status` (
`record_status_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`status` char(6) NOT NULL,
`status_description` varchar(15) NOT NULL,
`created_at` datetime NOT NULL,
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`record_status_id`,`status`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1
user
SHOW CREATE TABLE user
CREATE TABLE `user` (
`user_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`handle` varchar(45) NOT NULL,
`email` varchar(255) NOT NULL,
`password` char(64) DEFAULT NULL,
`password_salt` binary(1) DEFAULT NULL,
`first_name` varchar(50) NOT NULL,
`last_name` varchar(50) NOT NULL,
`gender` char(1) DEFAULT NULL,
`birthday` date NOT NULL,
`created_at` datetime NOT NULL,
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`user_status` char(6) DEFAULT NULL,
PRIMARY KEY (`user_id`),
KEY `usr_status_idx` (`user_status`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
and I tried adding the foreign key user_status of type CHAR using mysql Workbench as follows:
ALTER TABLE `mydatabase`.`user`
ADD CONSTRAINT `usr_status`
FOREIGN KEY (`user_status`)
REFERENCES `mydatabase`.`record_status` (`status`)
ON DELETE NO ACTION
ON UPDATE NO ACTION;
but I am getting the following error:
Error:
Executing SQL script in server
ERROR: Error 1005: Can't create table 'mydatabase.#sql-420_1b0' (errno: 150)
ALTER TABLE 'mydatabase'.'user'
ADD CONSTRAINT 'usr_status'
FOREIGN KEY ('user_status')
REFERENCES 'mydatabase'.'record_status'('status')
ON DELETE NO ACTION
ON UPDATE NO ACTION
SQL script execution finished: statements: 4 succeeded, 1 failed.
Question
My intention is to have the status column clearly show the current status for each user (ACTIVE, INACTV, DELETD) while still having the flexibility to join the record_status table with the user table using the record_status_id to find any rows with a given status for better performance.
I found a similar post here
Adding foreign key of type char in mysql
which suggests to change my primary key's collation but, how would that affect my user table?
Will I have to change the collation to the user_status field in my user table as well? The user table will be queried every time a user logs in and I am concerned about performance or any constraints this may cause.
I also intend to add a foreign key for the status to a few other tables as well. I would just like to know how this affects performance, or does it add any constraints?
Any input regarding my design will also be appreciated. Thank you for your help!
The issue you're facing isn't actually related to collation (though collation can be a cause of the error you're experiencing under different circumstances).
Your FOREIGN KEY constraint is failing because you don't have an index individually on record_status.status. You have that column as part of the composite PRIMARY KEY (record_status_id, status), but for successful foreign key constraint creation, both the referencing table and the referenced table must have indexes on exactly the columns used in the key relationship (in addition to the same data types).
Adding the FOREIGN KEY constraint implicitly creates the necessary index on the referencing table, but you must still ensure you have the corresponding index on the referenced table.
So given what you have now, if you added a single index on record_status.status, the constraint would correctly be created.
CREATE TABLE `record_status` (
`record_status_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`status` char(6) NOT NULL,
`status_description` varchar(15) NOT NULL,
`created_at` datetime NOT NULL,
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`record_status_id`,`status`),
-- This would make your relationship work...
KEY (`status`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1
However, I don't think that's the best course of action. I don't see a need for the composite primary key on (record_status_id, status), chiefly because the record_status_id is itself AUTO_INCREMENT and guaranteed to be unique. That column alone could be the PRIMARY KEY, while still adding an additional UNIQUE KEY on status to satisfy the foreign key constraint's indexing requirement. After all, it is not the combination of record_status_id and status which uniquely identifies each row (making a primary key)
CREATE TABLE `record_status` (
`record_status_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`status` char(6) NOT NULL,
`status_description` varchar(15) NOT NULL,
`created_at` datetime NOT NULL,
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
-- Primary only on record_status_id
PRIMARY KEY (`record_status_id`),
-- Additional UNIQUE index on status
UNIQUE KEY (`status`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1
About the design -- eliminating record_status_id...
Without knowing how the rest of your application currently uses record_status_id, I can't say for sure if it required by your application code. But, if you wish to make the actual status value easily available to other tables, and it is merely CHAR(6), it is possible that you actually have no need for record_status_id as an integer value. After all, if the status string is intended to be unique, then it is perfectly capable of serving as the PRIMARY KEY on its own, without any auto-increment integer key.
In that case, your record_status table would look like below, and your FOREIGN KEY constraint would correctly be added to users.
CREATE TABLE `record_status` (
-- Remove the auto_increment column!!
`status` char(6) NOT NULL,
`status_description` varchar(15) NOT NULL,
`created_at` datetime NOT NULL,
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
-- Status is unique, and therefore can be the PK on its own
PRIMARY KEY (`status`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1
Given this setup, here's a sample showing the successful creation of the tables and addition of the FK constraint.
You asked about performance implications of adding a status FK to other tables as well. It's tough to speculate on that without knowing the purpose, but if other tables share the same status values, then it makes sense to create their FK constraints to link to it in the same say you're doing with users. And if that's the case, I would recommend doing it the same way, wherein the status column is CHAR(6) (or consider changing all of them to VARCHAR(6)). The value of record_status.status still makes sense as the true primary key, and can be used as the FK in as many related tables as necessary.
In all but the most gigantic scale, there should be no appreciable performance difference between using an INT value and a CHAR(6)/VARCHAR(6) value as the foreign key. And the storage size difference between them is equally tiny. It isn't worth worrying about unless you must scale this to positively enormous proportions.

Simple add foreign key returns #1215 cannot add foreign key constraint

I am sure I am missing something simple.
RequestLog table:
CREATE TABLE `requestlog` (
`RequestID` int(10) unsigned NOT NULL AUTO_INCREMENT,
`RequestName` varchar(30) NOT NULL,
`RequestData` varchar(150) NOT NULL,
`RequestDate` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`Version` varchar(15) NOT NULL,
PRIMARY KEY (`RequestID`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
ResponseLog table:
CREATE TABLE `responselog` (
`ResponseID` int(10) unsigned NOT NULL AUTO_INCREMENT,
`FK_RequestID` int(10) NOT NULL,
`ResponseText` text NOT NULL,
PRIMARY KEY (`ResponseID`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
Trying to add a foreign key on ResponseLog.FK_RequestID with
ALTER TABLE ResponseLog
ADD FOREIGN KEY (FK_RequestID) REFERENCES RequestLog(RequestID)
Don't shoot me, what am I missing?
ALTER TABLE references tables ResponseLog and RequestLog. Your CREATE TABLE statements create tables named requestlog and responselog. Try changing your ALTER TABLE statement so that it uses table identifiers with the same case.
Also, and it is probably the main problem, the referenced fields have different data types. One is an int, the other an unsigned int. Data types have to match, otherwise the fields could become inconsistent. MySQL knows this and prevents you from creating a broken foreign key.

Error 150 when trying to import .sql file to phpmyadmin

I am trying to import a file *.sql from MySQL database on my server backup to new webhosting. I try to import via phpMyAdmin. I tried running XAMPP on local machine and import and am still getting the same error. Here is the create table statement:
CREATE TABLE `yv3nd_rokgallery_file_loves` (
`file_id` int(10) unsigned NOT NULL DEFAULT '0',
`kount` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`file_id`),
UNIQUE KEY `file_id` (`file_id`),
CONSTRAINT `yv3nd_file_loves_file_id_files_id` FOREIGN KEY (`file_id`)
REFERENCES `yv3nd_rokgallery_files` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8
I got: #1005 - Can't create table 'test.yv3nd_rokgallery_file_loves' (errno: 150)
I'm pretty new to this so any help to fix this error would be appreciated.
Here is more code:
CREATE TABLE yv3nd_rokgallery_files(
id int(10) unsigned NOT NULL AUTO_INCREMENT,
filename varchar(255) NOT NULL,
guid char(36) NOT NULL,
md5 char(32) NOT NULL,
title varchar(200) NOT NULL,
description text,
license varchar(255) DEFAULT NULL,
xsize int(10) unsigned NOT NULL,
ysize int(10) unsigned NOT NULL,
filesize int(10) unsigned NOT NULL,
type char(20) NOT NULL,
published tinyint(1) NOT NULL DEFAULT '0',
created_at datetime NOT NULL,
updated_at datetime NOT NULL,
slug varchar(255) DEFAULT NULL,
PRIMARY KEY (id), UNIQUE KEY id (id),
UNIQUE KEY guid (guid),
UNIQUE KEY yv3nd_files_sluggable_idx (slug),
KEY yv3nd_rokgallery_files_published_idx (published),
KEY yv3nd_rokgallery_files_md5_idx (md5),
KEY yv3nd_rokgallery_files_guid_idx (guid))
ENGINE=InnoDB DEFAULT CHARSET=utf8;
The errno 150 usually means that the foreign key constraint can't be created. Without seeing the rest of the file it is hard to say for sure, but I would guess that it is one of two things:
Your yv3nd_file_loves_file_id_files_id constraint may have been defined in another table as well. You can't create two constraints with the same name, that could potentially throw an error.
Another possibility is that you are creating a constraint on incorrect types. In this table your field_id is int(10). If in the yv3nd_rokgallery_files table your id variable is anything but that this will fail. For example: if in the other table it's int(9) this won't work.
If neither of these are correct, can you post the code for the yv3nd_rokgallery_files table?
EDIT
A third possibility is that the id field in the other table is not set as the primary key. This will also cause an error, because the foreign key of one table should match the primary key of another.
EDIT 2
Another possibility could be that you are creating the file_loves table before the files table. That would cause an error because you'd be creating a reference to a table that does not exist yet.
Errno 150 is what is reported if the FOREIGN KEY couldn't work.
The most common reason is that the data type of the foreign key column is different from the data type of the primary key column it references.
Your foreign key column is file_id int unsigned. The argument 10 for int(10) doesn't matter in this case. It's still an int unsigned.
Your primary key column is in table yv3nd_rokgallery_files, column id. You should double-check that that column is int unsigned. If it isn't, for example if it's a bigint or other size of int, or if it's not unsigned like file_id is, then the you'll get errno 150.
You must change one of the columns, either yv3nd_rokgallery_file_loves.file_id or yv3nd_rokgallery_files.id, so they use the same data type.
The errno 150 can also happen if the foreign key fails for other reasons. For example, table yv3nd_rokgallery_files must be an InnoDB table. Is it MyISAM?

mysql won't allow foreign key

Many people had this problem already, but there was no fitting solution in other posts.
I have two tables, one named "sales", the other named "host_flags". I would like to have a foreign key for host_flags.sales_id to sales.id, but mysql won't let me! I have primary indexes defined in each table, so I wonder why...
The host_flags table already has a foreign key on the column host_id, but even when I tried and created the foreign key for the sales id first, it wouldn't let me.
The tables look like:
CREATE TABLE `sales` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`email` varchar(255) DEFAULT NULL,
`password` varchar(255) DEFAULT NULL,
`creation` datetime DEFAULT NULL,
`lastupdate` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1;
CREATE TABLE `host_flags` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`host_id` int(11) DEFAULT NULL,
`sales_id` int(11) DEFAULT NULL,
`creation` datetime DEFAULT NULL,
`lastupdate` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `host_id6` (`host_id`),
CONSTRAINT `host_id6` FOREIGN KEY (`host_id`) REFERENCES `hosts` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CREATE TABLE `hosts` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`creation` datetime NOT NULL,
`lastupdate` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=32225 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
I get this error message:
MySQL said: Can't create table 'primarydata.#sql-191_1' (errno: 150)
Thanks!
Charles
SOLUTION FOUND
All ints of the primary indexes have to be either signed or unsigned - not mixed.
Typically:
I like to declare the FK constraints outside of the table definition after all tables have been constructed.
ALTER TABLE `tbl`
ADD CONSTRAINT `constr`
FOREIGN KEY `fk_id` REFERENCES `ftbl`(`id`)
ON UPDATE CASCADE
ON DELETE CASCADE;
This way I can make sure the problem isn't something like the datatype of tbl.fk_id not being the same as the one of ftbl.id (including UNSIGNED as #Devart said). Or not having declared ftbl.id as unique. Regardless of the order of declaration of the tables.
After i do this i can integrate the constraint back into the table definition and take into account the order in which the tables need to be created to allow the constraint to be added.
You problem:
-- creating the sales table
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
-- creating the host_flags table
`sales_id` int(11) DEFAULT NULL,
-- the sales.id is declared as unsigned
-- the host_flags.sales_id is declared signed
Additonally to Recursed's answer:
There is a requirement that foreign keys contstraints' names must be unique in database scope. Maybe changing the name will work?
There is also a huge thread on MySQL community forums about the problem containing several solutions for some specific situations.
Possible two errors:
Reference and referenced columns must have the same type - int(11) unsigned
Unknown referenced table hosts.

Foreign key constraint is incorrectly formed?

I got this error when create table: Foreign key constraint is incorrectly formed?
create table comment(
Comment_ID int UNSIGNED AUTO_INCREMENT not null,
User_1 varchar(50) not null,
Note_ID int(11) UNSIGNED not null,
PRIMARY key(Comment_ID),
CONSTRAINT `fk_1` FOREIGN KEY (`User_1`) REFERENCES `user` (`Dev_ID`),
CONSTRAINT `fk_2` FOREIGN KEY (`User_2`) REFERENCES `user` (`Dev_ID`),
CONSTRAINT `fk_3` FOREIGN KEY (`Note_ID`) REFERENCES `note`(`Note_ID`)
)ENGINE=InnoDB DEFAULT CHARSET=utf8;
it's OK when I remove fk_3.
This my note table
CREATE TABLE `note` (
`Dev_ID` varchar(50) NOT NULL,
`Note_ID` int(11) UNSIGNED NOT NULL,
`Title` varchar(200) NOT NULL,
`Time` datetime NOT NULL,
`Mood` int(11) NOT NULL,
`Body` varchar(3000) NOT NULL,
`Visible` tinyint(1) NOT NULL DEFAULT '1',
`Share` tinyint(1) NOT NULL DEFAULT '0',
`Update` tinyint(1) NOT NULL DEFAULT '0',
PRIMARY KEY (`Dev_ID`,`Note_ID`),
CONSTRAINT `fk_note_user` FOREIGN KEY (`Dev_ID`)
REFERENCES `user` (`Dev_ID`) ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8
Thanks for help!
That's because the primary key of the note table is (Dev_ID,Note_ID) but you are only referencing one of those columns (Note_ID) in your constraint.
A FK constraint must always consist of all PK columns.
Also make sure that both tables are innoDB.
In addition to the answers that have been given, you would also get this error if the field types did not match. For example, if you tried to create a foreign key constraint between a varchar field and an int field.
This problem occur because the column
`Note_ID` int(11) UNSIGNED NOT NULL
Is neither primary nor unique.
Just make it
`Note_ID` int(11) UNSIGNED NOT NULL UNIQUE
And it will work.
One more addition: charsets of the fields must match.
In the referenced table I had ascii as a default charset: DEFAULT CHARSET=ascii was reported by show create table. I tried to create the referencing table with DEFAULT CHARSET=utf and I got 'Foreign key constraint is incorrectly formed'.
After I changed this to DEFAULT CHARSET=ascii on the new table (the referencing one), it was created successfully.
Ensure the collation is the same on both fields. I had the same problem when one was latin-general-ci and the other was utf8_unicode_ci. Not sure why the collation changed on the one table but fixing this resolved the issue.