Why does MySQL not allow this foreign key? [duplicate] - mysql

This question already has answers here:
MySQL Creating tables with Foreign Keys giving errno: 150
(20 answers)
Closed 9 years ago.
I am using MySQL 5 to try and create two tables. Here are the two tables:
DROP TABLE IF EXISTS `users` ;
CREATE TABLE IF NOT EXISTS `users` (
`username` VARCHAR(50) not null ,
`password` VARCHAR(50) not null,
`enabled` boolean not null,
`accountNonExpired` boolean not null,
`accountNonLocked` boolean not null,
`credentialsNonExpired` boolean not null,
PRIMARY KEY (`username`)
) ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8;
DROP TABLE IF EXISTS `authorities` ;
create table IF NOT EXISTS `authorities` (
`username` VARCHAR(50) not null ,
`authority` varchar(50) not null,
foreign key (`username`) references `users` (`username`),
unique index authorities_idx_1 (username, authority)
) engine = InnoDb;
When I try to execute this statement, the users table is created but then I get the error:
Error Code: 1005
Can't create table 'dental.authorities' (errno: 150)
I am not seeing why this foreign key fails when the two referenced columns are identical. Is there

Foreign keys require both keys to have the same character set.
Add
DEFAULT CHARACTER SET = utf8;
to your second table CREATE instruction.
Edit: Oh boy looks like I'm late to the party.

Depending on your server version and settings, you might need to add
DEFAULT CHARACTER SET = utf8
to the CREATE TABLE statement for "authorities". That will match the character set of the referenced table.

check out following points:
i think DEFAULT CHARACTER SET = utf8; not provided to second table
1. The two tables must be ENGINE=InnoDB. (can be others: ENGINE=MyISAM
works too)
2. The two tables must have the same charset.
3. The PK column(s) in the parent table and the FK column(s) must be
the same data type.
4. The PK column(s) in the parent table and the FK column(s), if they
have a define collation type, must have the same collation type;
5. If there is data already in the foreign key table, the FK column
value(s) must match values in the parent table PK columns.
6. And the child table cannot be a temporary table.
Hope this helps.

Related

Error when foreign referencing in mySQL (Error 3780)

I am making two tables and I want the personOne column from table b to reference the person column on table a, but for some reason it doesn't work.
I have the below code as an example:
create table a(
person varchar(20),
cost varchar(10) not Null
)character set latin1
collate latin1_general_ci;
create table b(
personOne varchar(20),
personTwo varChar(2) not null,
key person_index (personOne),
CONSTRAINT C FOREIGN KEY (personOne) references a(person)
) engine=InnoDB default charset=latin1;
It is telling me an error:
Error Code: 3780. Referencing column 'personOne' and referenced column 'person' in foreign key constraint 'C' are incompatible.
I tried to to set table a engine to InnoDB, but that didn't work. I researched the problem more but couldn't figure out how to fix it.
The two columns must have the same collation. I'm guessing your table b is using the default collation for old versions of MySQL, which is latin1_swedish_ci.
You might like to review this checklist for foreign keys: https://stackoverflow.com/a/4673775/20860
I suggest the best choice is to declare both a and b tables with character set utf8mb4 and collation utf8mb4_unicode_520_ci if your version of MySQL is new enough to support it.
Here I had to first define a primary key in a:
ALTER TABLE a ADD PRIMARY KEY (person);
And pass the COLLATE value of a:
CREATE TABLE b (
...
)ENGINE=InnoDB
DEFAULT CHARSET=latin1
COLLATE latin1_general_ci;
I got the same error code.
Although it may not help your situation, my problem was;
The ID column in all my tables is set as INT UNSIGNED but I was using a foreign key of type INT signed.

Foreign key constraint is incorrectly formed (MariaDB)

I'm just trying to execute a MySQL file within MariaDB, but it gives me the following error: ERROR 1005 (HY000) at line 14: Can't create table roundcube.calendars (errno: 150 "Foreign key constraint is incorrectly formed")
That's the SQL query: https://pastebin.com/4FBA30JM
Unfortunately I can't post it here since it kinda messes up the formatting.
Here's your calendars table definition:
CREATE TABLE IF NOT EXISTS `calendars` (
`calendar_id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`user_id` int(10) UNSIGNED NOT NULL DEFAULT '0',
`name` varchar(255) NOT NULL,
`color` varchar(8) NOT NULL,
`showalarms` tinyint(1) NOT NULL DEFAULT '1',
PRIMARY KEY(`calendar_id`),
INDEX `user_name_idx` (`user_id`, `name`),
CONSTRAINT `fk_calendars_user_id` FOREIGN KEY (`user_id`)
REFERENCES `users`(`user_id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=INNODB CHARACTER SET utf8 COLLATE utf8_general_ci;
I tested this out in a sandbox and the statement is fine. There's nothing wrong with it.
However, I don't see a users table in your linked code sample. Before you can create a table with a foreign key, the following must be true:
The referenced table (users in your case) must exist.
The referenced table must use the InnoDB storage engine.
The referenced column (user_id) must exist in the table.
The referenced column must have exactly the same data type as the foreign key column that references it. In your case, this is INT UNSIGNED (The integer length argument (10) is optional and may be different in the two tables).
The referenced column must be the leftmost column of a KEY. Ideally it should be the entire PRIMARY KEY or UNIQUE KEY, to be compatible with standard SQL. Technically, InnoDB also allows foreign keys to reference non-unique keys, but this is discouraged.
So you must have a table at least like the following already existing in your database:
CREATE TABLE `users` (
`user_id` int(10) UNSIGNED NOT NULL,
PRIMARY KEY (`user_id`)
) ENGINE=INNODB CHARACTER SET utf8 COLLATE utf8_general_ci;
I had to create this table in my sandbox before your calendars table definition would work.

Why is this foreign key constraint not working?

I'm creating a new table who will have relationships with an existing table. The new table has a column user_id which references a userid column on another table (the ID of a user in the users table).
I have the following table:
CREATE TABLE `ads` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
-- Other columns...
)
DEFAULT CHARACTER SET utf8
COLLATE utf8_unicode_ci
ENGINE = InnoDB;
Adding a referencing column
ALTER TABLE `ads` ADD `user_id` INT(11) NOT NULL
Which references the following column
CREATE TABLE users
(
userid INT(11) PRIMARY KEY NOT NULL AUTO_INCREMENT,
-- Other irrelevant fields...
);
And finally my key definition:
ALTER TABLE `ads` ADD CONSTRAINT ads_user_id_foreign FOREIGN KEY (`user_id`) REFERENCES `users` (`userid`)
But for some reason I still get an error:
SQLSTATE[HY000]: General error: 1215 Cannot add foreign key constraint (SQL: alter table `ads` add constraint ads_user_id_foreign foreign key (`user_id`) references `users` (`userid`))
Note: I don't believe it's of much relevance, but I'm using Laravel's query builder to create the new table. I'm getting these queries from PHPStorm's Copy DDL feature to show you the equivalent "vanilla MySQL query".
Okay, so I figured it out. In my case, I also needed to change the engine, charset, and collation of the users table. IT was set to MyISAM, latin1, and latin1_swedish_ci, respectively.
I did say I was using Laravel, so here are the statements I used to fix that:
DB::statement('ALTER TABLE users CONVERT TO CHARACTER SET utf8 COLLATE utf8_unicode_ci');
DB::statement('ALTER TABLE users ENGINE=InnoDB;');
I'll try to leave a generic answer here for those who find this post in the future.
Things to check when foreign keys aren't working:
1. Make sure that the columns are setup identically
I use an IDE (PHPStorm) that allows me to get some DDL from existing tables. I paste that somewhere and find the columns in question to see if they're defined correctly.
2. Check table status for inconsistencies
You can check all tables' statuses with SHOW TABLE STATUS. You'll get a result that looks like this (obviously this depends on your IDE):
Make sure that engine and collation match in both tables
• If you notice that your engine is wrong (it should be InnoDB), you can fix it with
ALTER TABLE <table_name> ENGINE=InnoDB;
• If you notice that your collation is wrong, you can fix it with
alter table <table_name> convert to character set <CHARSET> collate <COLLATION>;
(where a charset might be utf8 and a collation might be utf8_unicode_ci)

MySQL Errno 150

I'm creating a few simple tables and I can't get passed this foreign key error and I'm not sure why. Here's the script below.
create TABLE Instructors (
ID varchar(10),
First_Name varchar(50) NOT NULL,
Last_Name varchar(50) NOT NULL,
PRIMARY KEY (ID)
);
create table Courses (
Course_Code varchar(10),
Title varchar(50) NOT NULL,
PRIMARY KEY (Course_Code)
);
create table Sections (
Index_No int,
Course_Code varchar(10),
Instructor_ID varchar(10),
PRIMARY KEY (Index_No),
FOREIGN KEY (Course_Code) REFERENCES Courses(Course_Code)
ON DELETE cascade
ON UPDATE cascade,
FOREIGN KEY (Instructor_ID) REFERENCES Instructors(ID)
ON DELETE set default
);
Error Code: 1005. Can't create table '336_project.sections' (errno: 150)
My data types seem identical and the syntax seems correct. Can anyone point out what I'm not seeing here?
I'm using MySQL Workbench 5.2
This error also occurs if you are relating columns of different types, eg. int in the source table and BigInt in the destination table.
If you're using the InnoDB engine, the ON DELETE SET DEFAULT is your problem. Here's an excerpt from the manual:
While SET DEFAULT is allowed by the MySQL Server, it is rejected as invalid by InnoDB. CREATE TABLE and ALTER TABLE statements using this clause are not allowed for InnoDB tables.
You can use ON DELETE CASCADE or ON DELETE SET NULL, but not ON DELETE SET DEFAULT. There's more information here.
You can run
SHOW ENGINE INNODB STATUS
to read the reason of the failure in a human readable format
e.g.
------------------------
LATEST FOREIGN KEY ERROR
------------------------
150331 15:51:01 Error in foreign key constraint of table foobar/#sql-413_81:
FOREIGN KEY (`user_id`) REFERENCES `foobar`.`users`(`id`) ON DELETE SET NULL ON UPDATE CASCADE:
You have defined a SET NULL condition though some of the columns are defined as NOT NULL.
In order to create a FOREIGN KEY with reference to another table, the keys from both tables should be PRIMARY KEY and with the same datatype.
In your table sections, PRIMARY KEY is of different datatype i.e INT but in another table, it's of type i.e VARCHAR.
It may also be the case if you are not specifying the ON DELETE at all but are trying to reference a MYISAM table from InnoDB table:
CREATE TABLE `table1`(
`id` INT UNSIGNED NOT NULL,
`name` VARCHAR(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MYISAM CHARACTER SET UTF8;
CREATE TABLE `table2`(
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`table1_id` INT UNSIGNED NOT NULL,
`some_value` VARCHAR(255) NOT NULL,
PRIMARY KEY (`id`),
KEY `fk_table1_id`(`table1_id`),
CONSTRAINT FOREIGN KEY (`table1_id`) REFERENCES `table1`(`id`)
) ENGINE=INNODB CHARACTER SET UTF8;
The above will throw errno 150. One need to change the first table to InnoDB too for this to work.
It is failing on the
ON DELETE set default
I have not come across that before and I am not seeing it in the manuals either ( but then it is late )
Update
just seen this in the manual
While SET DEFAULT is allowed by the MySQL Server, it is rejected as
invalid by InnoDB. CREATE TABLE and ALTER TABLE statements using this
clause are not allowed for InnoDB tables.
I guess you may be using InnoDB tables ?
For completeness sake - you will also get this error if you make a foreign reference to a table that isn't defined at the time;
Here Problem is in database engine ( table1 MYISAM and table2 ENGINE).
To set FOREIGN KEYs,
Both table must be in same ENGINE and same charset.
PK column in parent and FK column must be in same data type and same collation type.
Hope you got an idea.
Make sure that table type is InnoDB, MyISAM does not support foreign key, afaik.

MySQL: Problem with a specific reference

I have two tables. On is a table that contains IP Ranges and their respective country attributions (IPGEO table). The other is a table which simply keeps track of the last country the site was accessed from on a per user basis. The idea is that, if the user suddenly accesses the site from another country, I notify the user about this via email.
Now for the actual tables. I have these two:
The IPGeo table that contains the IP ranges
CREATE TABLE IF NOT EXISTS `politiker_lu`.`IPGeo` (
`IPFrom` INT(11) NOT NULL ,
`IPTo` INT(11) NOT NULL ,
`code2` VARCHAR(2) NOT NULL ,
`code3` VARCHAR(3) NOT NULL ,
`Country` VARCHAR(45) NOT NULL ,
INDEX `index1` (`IPFrom` ASC) ,
INDEX `index2` (`IPTo` ASC) )
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8;
Then, there is the user_geo table that tracks the last country from which the user accessed the site.
CREATE TABLE IF NOT EXISTS `politiker_lu`.`user_geo` (
`fi_user` INT(10) UNSIGNED NOT NULL ,
`fi_country` VARCHAR(3) NOT NULL ,
`timestamp` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ,
PRIMARY KEY (`fi_user`) ,
INDEX `fk_user_geo_1` (`fi_user` ASC) ,
CONSTRAINT `fk_user_geo_1`
FOREIGN KEY (`fi_user` )
REFERENCES `politiker_lu`.`user` (`id_user` )
ON DELETE CASCADE
ON UPDATE CASCADE)
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8;
These are the tables as they exist. I now want to reference these two tables as follows:
ALTER TABLE `politiker_lu`.`user_geo`
ADD CONSTRAINT `fk_user_geo_IPGeo1`
FOREIGN KEY (`fi_country` )
REFERENCES `politiker_lu`.`IPGeo` (`code3` )
ON DELETE CASCADE
ON UPDATE CASCADE
, ADD INDEX `fk_user_geo_IPGeo1` (`fi_country` ASC) ;
That Statement however fails with errno 150. Both tables are utf8, both columns have the same data-type. Am I missing something vital here?
Notes
The table user exists and has all the references and is actually irrelevant to the problem. I left it so that I didn't need to edit the statement too much.
You need to add a unique index or a primary key on the IPGeo.code3 column in order to reference it with a foreign key.
You can see the error by running show engine innodb status\G and looking under the LATEST FOREIGN KEY ERROR section. The error probably looks something like this:
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.
Note that the internal storage type of ENUM and SET changed in
tables created with >= InnoDB-4.1.12, and such columns in old tables
cannot be referenced by such columns in new tables.
See http://dev.mysql.com/doc/refman/5.1/en/innodb-foreign-key-constraints.html
for correct foreign key definition.