In my local environment database(localhost:3306, mysql 5.7.20), everything works fine.
but In aws RDS database(mysql 5.7.22), Unhandled rejection SequelizeDatabaseError: Cannot add foreign key constraint error occur.
full log is below.
Executing (default):
CREATE TABLE IF NOT EXISTS `folders`
(`id` CHAR(36) BINARY , `folderName` VARCHAR(255),
`folderCoverImage` VARCHAR(255), `createdAt` DATETIME NOT NULL,
`updatedAt` DATETIME NOT NULL, `fk_user_id` CHAR(36) BINARY,
`fk_category_id` CHAR(36) BINARY,
PRIMARY KEY (`id`),
FOREIGN KEY (`fk_user_id`) REFERENCES `users` (`id`)
ON DELETE CASCADE ON UPDATE RESTRICT,
FOREIGN KEY (`fk_category_id`) REFERENCES `categories` (`id`)
ON DELETE SET NULL ON UPDATE CASCADE) ENGINE=InnoDB;
Unhandled rejection SequelizeDatabaseError: Cannot add foreign key constraint
users:
CREATE TABLE IF NOT EXISTS `users` (`id` CHAR(36) BINARY , `username` VARCHAR(255), `email` VARCHAR(255) UNIQUE, `socialProvider` VARCHAR(255), `profileImg` TEXT, `createdAt` DATETIME NOT NULL, `updatedAt` DATETIME NOT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;
categories:
CREATE TABLE IF NOT EXISTS `categories` (`id` CHAR(36) BINARY , `name` VARCHAR(255) UNIQUE, `createdAt` DATETIME NOT NULL, `updatedAt` DATETIME NOT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Executing (default): SHOW INDEX FROM categories
and my node.js code here.
Folder.associate = function associate () {
Folder.belongsTo(User, {
foreignKey: 'fk_user_id',
onDelete: 'CASCADE',
onUpdate: 'restrict'
});
Folder.hasMany(Work, {
as: 'Work',
foreignKey: 'fk_folder_id',
onDelete: 'CASCADE',
onUpdate: 'restrict'
});
Folder.belongsTo(Category, {
as: 'Category',
foreignKey: 'fk_category_id'
});
};
also, table users, categories, post, tag have existed.
Create table order is here http://sqlfiddle.com/#!9/2162ca
I don't know why it dosn't work at aws RDS.
Can you check the order of create tables. When you change the order so that table (whose primary key is being referenced) already exists the error willnot occur.
Possible duplicate here
The problem might be the database is not empty. In such case, when one of the rows does not fulfill foreign key requirement, adding the requirement to the whole table will fail.
Make sure all the rows on the AWS RDS can fulfill the requirement and that their foreign records exist.
Example:
let's say you create a table with books and user_id column. You decide that user_id with a value of "0" means no user was assigned to the row (book is still in the library).
Then, the code changes and you implement user_id as a foreign key (user_id should now point to "user" table, "id" column
which you would normally do via:
ALTER TABLE database.books
ADD FOREIGN KEY book_user_id(user_id) REFERENCES user(id);
Now, if you already have books in your database with user_id column having "0" value, the query will fail, because there are records that point to non-existing user (with id of "0").
To fix this, you need to update the records with broken soon-to-be reference first.
In this particular case, creatng a "librarian" user with some id of i.e 123, then doing:
UPDATE books set user_id=123 WHERE user_id=0;
Would do the trick and allow you to create the foreign key without issue.
Related
I have the following tables in my MySQL database:
CREATE TABLE `User` (
`id` char(25) CHARACTER SET utf8 NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `email_UNIQUE` (`email`(191))
);
CREATE TABLE `Post` (
`id` char(25) NOT NULL,
`authorId` char(25) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `authorId` (`authorId`),
CONSTRAINT `Post_ibfk_1` FOREIGN KEY (`authorId`) REFERENCES `User` (`id`)
);
CREATE TABLE `_PostToUser` (
`A` char(25) CHARACTER SET utf8 NOT NULL,
`B` char(25) CHARACTER SET utf8 NOT NULL,
UNIQUE KEY `PostToUser_AB_unique` (`A`,`B`),
KEY `B` (`B`),
CONSTRAINT `_PostToUser_ibfk_1` FOREIGN KEY (`A`) REFERENCES `Post` (`id`) ON DELETE CASCADE,
CONSTRAINT `_PostToUser_ibfk_2` FOREIGN KEY (`B`) REFERENCES `User` (`id`) ON DELETE CASCADE
);
The relationship between User and Post right now is managed via the _PostToUser JOIN table.
However, I want to get rid of this extra JOIN table and simply have a foreign key reference from Post to User, so I ran this query to create the foreign key:
ALTER TABLE `Post` ADD COLUMN `authorId` char(25);
ALTER TABLE `Post` ADD FOREIGN KEY (`authorId`) REFERENCES `User` (`id`);
Now, I'm wondering what SQL query I need to run in order to migrate the data from the JOIN table to the new authorId column? If I understand correctly, I need a query that reads all the rows from the _PostToUser relation table and for each row:
Finds the respective Post record by looking up the value from column A
Inserts the value from column B as the value for authorId into that Post record
Note that I am aware that this changes the relationship from m-n and restricts it to 1-n: One post can at most have one author. One author/user can write many posts.
I'm basically looking for the equivalent of this PostgreSQL statement:
UPDATE "Post" post
SET "authorId" = post_to_user."B"
FROM "_PostToUser" post_to_user
WHERE post_to_user."A" = post."id";
Ensure that _PostToUser.A values are unique (no duplicated values). If exists - edit your data (remove excess records, for example).
Execute
UPDATE Post, _PostToUser
SET Post.authorId = _PostToUser.B
WHERE Post.id = _PostToUser.A
Ensure that there is no NULLs in Post.authorId
I'm having a problem creating a database in MySQL.
The error code:'Error code 1215: cannot add foreign key constraint' pops up when i try to implement my changes. I've paid attention to all the necessary things but i can't find the solution.
This error only happened after i added some tables after having made an initial database(which did work), so hopefully i'm not dealing with this problem throughout the whole project.
Here's a snippet of the code in which the error occurs, the foreign key that's not working correctly is 'tournament_id' referencing to 'id' in tournament:
CREATE DATABASE allin;
USE allin;
CREATE TABLE employee (
phone_number char(12) NOT NULL,
birth_date date NOT NULL,
tournament_id int NOT NULL AUTO_INCREMENT,
PRIMARY KEY(phone_number),
FOREIGN KEY(tournament_id) REFERENCES tournament(id) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Second table:
CREATE TABLE tournament (
id int NOT NULL AUTO_INCREMENT,
date date NOT NULL,
time time NOT NULL,
cost decimal(5,2) NOT NULL,
min_players int NOT NULL,
min_age int NOT NULL,
max_age int NOT NULL,
location_id int NULL,
winner_id int NULL,
type varchar(40) NULL,
PRIMARY KEY(id),
FOREIGN KEY(winner_id) REFERENCES player(id) ON DELETE SET NULL ON UPDATE CASCADE,
FOREIGN KEY(location_id) REFERENCES event_location(id) ON DELETE SET NULL ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
The issue is here:
FOREIGN KEY(tournament_id) REFERENCES tournament(id) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
the above query is of CREATE TABLE employee. In this query, you are creating a FOREIGN KEY that refers to tournament(id), but as of now there is no tournament table exist in the specified database as the tournament table create query is reside below in the sequence.
I layman terms we can say, you are trying to refer a table column that
do not exist.
So to resolve this, run all you parent table creation query first, and than child table.
tournament_id int NOT NULL AUTO_INCREMENT,
PRIMARY KEY(phone_number)
Hey, I don't think you could set another primary key while an "auto increment" already exist
UPDATE: I have a ticket into my hosting provider (FatCow) as they are able to duplicate the issue. I will post any conclusions here.
I have a MySQL database like so:
table || pk
-----------
performers -> pID
genres -> gID
venues -> vID
I also have an events table that looks something like this:
eID (PK)
ePerformer (INDEX)
eGenre (INDEX)
eVenue (INDEX)
They are all the same type: INT(11). All of the tables are InnoDB. I want to setup the relationships in phpMyAdmin using the Relation View on the events table, but when I try to save:
ePerformer: performers->pID ON DELETE RESTRICT, ON UPDATE RESTRICT
eGenre: genres->gID ON DELETE RESTRICT, ON UPDATE RESTRICT
etc...
I get this error back for each field: No index defined!
I thought perhaps I was doing it backwards, so I tried setting each relationship from the other tables but I'm getting the same error.
What gives?
Using a similar structure I am able to create the relations. You've already checked several of the obvious things (primary key on the referenced keys, InnoDB, etc).
When I first created the events table, using the phpMyAdmin dropdown to select INDEX for each of the three fields you indicate, it created a composite index on all three fields, which didn't work; I had to remove that index and manually create an INDEX on each field individually.
The composite index:
The working individual indexes:
You could try the Designer feature (which requires you to set up the "phpMyAdmin configuration storage"); I find it superior to the Relation View when manipulating relations.
From the events table (I know, you already said you were on the proper table), click the Structure tab and next the Relation View link, you should be able to do this:
In this case I had already created the events_ibfk_1 relationship through Designer and fk_venue through Relation View; this screenshot was taken just prior to creating the fk_performer one so what you see here is exactly what I had in place before clicking "Save".
Not sure if that helps any, but I'm able to do it with what you've provided...so maybe if it still doesn't work you can export your complete existing table structure and I'll try to make that work.
For what it's worth, here's the export of the table structure I had working:
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
SET time_zone = "+00:00";
CREATE TABLE IF NOT EXISTS `events` (
`eID` int(11) NOT NULL,
`ePerformer` int(11) NOT NULL,
`eGenre` int(11) NOT NULL,
`eVenue` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CREATE TABLE IF NOT EXISTS `genres` (
`gID` int(11) NOT NULL,
`g` varchar(255) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CREATE TABLE IF NOT EXISTS `performers` (
`pID` int(11) NOT NULL,
`p` varchar(255) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CREATE TABLE IF NOT EXISTS `venues` (
`vID` int(11) NOT NULL,
`v` varchar(255) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
ALTER TABLE `events`
ADD PRIMARY KEY (`eID`), ADD KEY `i_perf` (`ePerformer`), ADD KEY `i_genre` (`eGenre`), ADD KEY `i_venue` (`eVenue`);
ALTER TABLE `genres`
ADD PRIMARY KEY (`gID`);
ALTER TABLE `performers`
ADD PRIMARY KEY (`pID`);
ALTER TABLE `venues`
ADD PRIMARY KEY (`vID`);
ALTER TABLE `events`
ADD CONSTRAINT `fk_performer` FOREIGN KEY (`ePerformer`) REFERENCES `performers` (`pID`),
ADD CONSTRAINT `events_ibfk_1` FOREIGN KEY (`eGenre`) REFERENCES `genres` (`gID`),
ADD CONSTRAINT `fk_venue` FOREIGN KEY (`eVenue`) REFERENCES `venues` (`vID`);
I have a problem with mutual constraints.
I want to have two tables each having a constraint on the other one.
I'm working with Doctrine2 (but it's not related to the problem), here is my simplified code:
SQL:
CREATE TABLE IF NOT EXISTS `thread` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`last_message_id` int(11) DEFAULT NULL,
`subject` varchar(255) NOT NULL
PRIMARY KEY (`id`),
UNIQUE KEY `UNIQ_C023F2BBBA0E79C3` (`last_message_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
ALTER TABLE `thread`
ADD CONSTRAINT `FK_C023F2BBBA0E79C3` FOREIGN KEY (`last_message_id`) REFERENCES `message` (`id`);
CREATE TABLE IF NOT EXISTS `message` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) DEFAULT NULL,
`thread_id` int(11) DEFAULT NULL,
`body` longtext NOT NULL
PRIMARY KEY (`id`),
KEY `IDX_9E4E8B5FA76ED395` (`user_id`),
KEY `IDX_9E4E8B5FE2904019` (`thread_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
ALTER TABLE `message`
ADD CONSTRAINT `FK_9E4E8B5FE2904019` FOREIGN KEY (`thread_id`) REFERENCES `thread` (`id`) ON DELETE CASCADE;
Doctrine2 mapping (which generated the SQL code above):
<?php
class Thread
{
/* #ORM\OneToOne() */
private $lastMessage;
}
class Message
{
/* #ORM\ManyToOne() */
private $thread;
}
And when I try to delete either a thread or a message, I get (logically) the error:
Integrity constraint violation: 1451 Cannot delete or update a parent row: a foreign key constraint fails ('thread', CONSTRAINT 'FK_C023F2BBBA0E79C3' FOREIGN KEY ('last_message_id') REFERENCES 'message' ('id'))
So, is there a way to avoid this error?
Or should I forget mutual constraints?
Anything?
I want to add that I want to keep the last_message_id because I want to display the threads with infos on their last message, and making a (paginated) query without this reference to the last message was a total nightmare...
Thanks!
Circular paths in FOREIGN KEY constraints are hard to deal with and your problem is an example. If you can avoid them, do that. Here's one way to redesign your tables:
First, add a UNIQUE KEY in table message on (thread_id, message_id) (or make it the Primary Key, if Doctrine can do that. That would mean - for MySQL- that message(id) would not be auto-incremented but produced by the ORM. You may don't want that if you plan to have applications that access the database directly or through other ORMs).
Then move the last_message_id to a new table that has a 1-to-1 relationship with message though the compound (thread_id, message_id). In this table, the thread_id would be Unique so every thread has exactly one last message.
I'll write the SQL code here. This page will help you with the Doctrine code which may produce slightly different structure: Compound Primary and Foreign Keys
CREATE TABLE IF NOT EXISTS `thread` (
`id` int(11) NOT NULL AUTO_INCREMENT,
---`last_message_id` int(11) DEFAULT NULL, --- REMOVED: last_message
`subject` varchar(255) NOT NULL
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `message` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) DEFAULT NULL,
`thread_id` int(11) NOT NULL, --- why was it NULL ?
`body` longtext NOT NULL
PRIMARY KEY (`id`),
KEY `IDX_9E4E8B5FA76ED395` (`user_id`),
---KEY `IDX_9E4E8B5FE2904019` (`thread_id`), --- REMOVED, not needed any more
--- because we have a this key
UNIQUE KEY (thread_id, id) --- ADDED, needed for the FK below
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
ALTER TABLE `message`
ADD CONSTRAINT `FK_9E4E8B5FE2904019`
FOREIGN KEY (`thread_id`)
REFERENCES `thread` (`id`)
ON DELETE CASCADE;
And the new table, to store the last message for each thread:
CREATE TABLE IF NOT EXISTS `thread_last_message` (
`message_id` int(11) NOT NULL,
`thread_id` int(11) NOT NULL,
PRIMARY KEY (`thread_id`),
KEY (`thread_id`, message_id`),
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
ALTER TABLE `thread_last_message` --- which just means
ADD CONSTRAINT `FK_something` --- that every
FOREIGN KEY (`thread_id`, `message_id`) --- thread's last message
REFERENCES `message` (`thread_id`, `id`) --- is a message
ON DELETE CASCADE;
Another possibility is to have the thread(last_message_id) column NULL and change the FK constraints appropriately (as #Eric's proposal). This is less fussy in the design phase and you have one table less to deal with. You have to be careful with the order of inserts and deletes in this approach - as your example shows.
As a third option, have you thought if you really need a thread(last_message_id) column in your table? Couldn't this be a computed (from the two tables) value and you skip the whole issue? If it was a best_message_id I would understand this but the last message is just the last row in another table, ordered by time. You can find that with a query and you don't need to store it (again) in the database, unless there are performance reasons.
The best solution I can think of would be to add a ON DELETE CASCADE constraint to the FK on the Thread table. That way if you delete the thread, the associated messages would be automatically deleted as well.
Similarly, you would need to add a ON DELETE SET NULL constraint on the Messages table FK so that if you deleted the last message in a Thread, it would set the last_message_id to NULL on the Thread table.
Or you could just do logical (soft) deletes instead of hard deletes, which would also solve the problem.
ETA:
Now that you've posted the constraints, this is the one you would have to modify:
ALTER TABLE `thread`
ADD CONSTRAINT `FK_C023F2BBBA0E79C3` FOREIGN KEY (`last_message_id`)
REFERENCES `message` (`id`) ON DELETE SET NULL;
If you have mutual constraints (ie every message has a thread and every thread has a message) why can't you combine this into one table? Seems to make more sense that way
This solution does not require altering the schema, which by the way, you have to undo.
If you want to remove a thread, the messages on that thread do not make sense either, so:
-- break one end of the mutual constraint
update thread set last_message_id = NULL where id = <thread_id_to_delete>;
delete from message where thread_id = <thread_id_to_delete>
delete from threads where id = <thread_id_to_delete>
(Disclaimer: I did not test this exact code, but a similar one)
I have the following tables:
specie (MyIsam)
image (InnoDB)
specie_map (InnoDB)
The specie_map table should map an image to a specie, and therefore has the following columns:
specie_id
image_id
Both are int 11, just like the id columns of the specie and image tables. I know I can't create a foreign key between specie_id and specie=>id, since the specie table is a MyIsam table. However, I would expect it to be possible to create a foreign key between image_id and image=>id.
I can create that foreign key and it will save it, however, the CASCADE action I have associated with it does not work. When I delete an image, it does not delete the specie_map entry that is associated with it. I would expect this to work, as this foreign key is between InnoDB tables. Both columns are indexed and of the same data type.
Is this a limitation of MySQL, or am I doing something else wrong?
Update: as requested hereby the table definitions. I have snipped unimportant columns:
-- ----------------------------
-- Table structure for `image`
-- ----------------------------
DROP TABLE IF EXISTS `image`;
CREATE TABLE `image` (
`id` int(11) NOT NULL auto_increment,
`guid` char(36) default NULL,
`title` varchar(255) NOT NULL,
`description` text,
`user_id` int(11) NOT NULL,
`item_id` int(11) default NULL,
`date_uploaded` timestamp NOT NULL default '0000-00-00 00:00:00',
`date_created` timestamp NOT NULL default '0000-00-00 00:00:00',
`date_modified` timestamp NOT NULL default '0000-00-00 00:00:00',
`status` enum('softdeleted','tobedeleted','active') default 'active',
PRIMARY KEY (`id`),
KEY `image_user` (`user_id`),
KEY `image_item` (`item_id`),
KEY `image_mod_by` (`moderated_by`),
CONSTRAINT `image_mod_by` FOREIGN KEY (`moderated_by`) REFERENCES `user` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT `image_user` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='stores image data (not file data)';
-- ----------------------------
-- Table structure for `specie`
-- ----------------------------
DROP TABLE IF EXISTS `specie`;
CREATE TABLE `specie` (
`id` int(11) NOT NULL auto_increment,
`name` varchar(256) NOT NULL,
`commonname` varchar(256) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=22 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;
-- ----------------------------
-- Table structure for `specie_map`
-- ----------------------------
DROP TABLE IF EXISTS `specie_map`;
CREATE TABLE `specie_map` (
`id` int(11) NOT NULL auto_increment,
`image_id` int(11) NOT NULL,
`specie_id` int(11) NOT NULL,
`user_id` int(11) NOT NULL,
`karma` int(11) NOT NULL,
`date_created` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `image_id` (`image_id`),
KEY `specie_id` (`specie_id`),
CONSTRAINT `specie_map_ibfk_1` FOREIGN KEY (`image_id`) REFERENCES `image` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Foreign keys works only with InnoDb in mysql. MyISAM doesn't support them (the statements are ignored).
And is there any reason why you mix multiple DB engines?
I think you should post the exact DDL statements you used when you attempted to create these tables and the foreign key. Foreign keys between innodb tables work fine, but there are still a few things to look out for:
0) Both tables must be InnoDB. This was already highlighted by the other posters and this is probably the immediate cause of your problem.
1) the data type of the referencing columns (those that make up the foreign key) and their respective referenced columns should be the same. For example, you can't create a foreign key constrain on an INT UNSIGNED column to a plain INT column.
2) if the foreign key is created as part of the table DDL, be sure to put the foreign key definition in the constraints section, that is, below all column definitions. For example:
CREATE TABLE parent (
id int unsigned PRIMARY KEY
);
CREATE TABLE child (
parent_id int unsigned
, foreign key (parent_id)
references parent (id)
);
will work but this:
CREATE TABLE child (
parent_id int unsigned
foreign key references parent (id)
);
won't. It will fail silently because MySQL's parser ignores these types of constraint definitions even before InnoDB gets to create the table (silly, but that's how it is)
3) There must be an index over all the referenced columns. Usually the referenced columns will together make up a primary key or a unique constraint anyway, but it is your job to define this before defining the foreign key.
Final word of advice: if you think your DDL is ok but you still get an error when you execute it, for example like this:
ERROR 1005 (HY000): Can't create table 'test.child' (errno: 150)
Warning (Code 150): Create table 'test/child' with foreign key constraint failed. There is no index in the referenced table where the referenced columns appear as the first columns.
Error (Code 1005): Can't create table 'test.child' (errno: 150)
Then these errors may still not reveal the true nature of the error (silly again, but that's how it is). To shed more light on it, run this command immediately after your attempt to create the foreign key:
SHOW ENGINE INNODB STATUS;
This will give you a bunch of status info, and one section there looks like this:
------------------------
LATEST FOREIGN KEY ERROR
------------------------
120122 11:38:28 Error in foreign key constraint of table test/child:
foreign key (parent_id) references parent (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.
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.5/en/innodb-foreign-key-constraints.html
for correct foreign key definition.
As you can see, this gives a bit more information and reveals the true problem, namely "column types in the table and the referenced table do not match for constraint"
So please, post your actual DDL, I'm sure there is a problem in there somewhere.