Since version 7.3 MySQL Cluster should be capable of foreign key constraints. But here is what happens:
DROP TABLE IF EXISTS t2;
DROP TABLE IF EXISTS t1;
CREATE TABLE t1 (
id INT PRIMARY KEY
) ENGINE='InnoDB';
CREATE TABLE t2 (
id INT PRIMARY KEY,
t1id INT
) ENGINE='InnoDB';
ALTER TABLE t2
ADD CONSTRAINT t2t1 FOREIGN KEY (t1id) REFERENCES t1 (id)
ON DELETE CASCADE ON UPDATE CASCADE;
This is using InnoDB and everything works just fine. Now try it with NDB:
DROP TABLE IF EXISTS t2;
DROP TABLE IF EXISTS t1;
CREATE TABLE t1 (
id INT PRIMARY KEY
) ENGINE='NDB';
CREATE TABLE t2 (
id INT PRIMARY KEY,
t1id INT
) ENGINE='NDB';
ALTER TABLE t2
ADD CONSTRAINT t2t1 FOREIGN KEY (t1id) REFERENCES t1 (id)
ON DELETE CASCADE ON UPDATE CASCADE;
-- ERROR 150 (HY000): Cannot add foreign key constraint
And now the weird part:
DROP TABLE IF EXISTS t2;
DROP TABLE IF EXISTS t1;
CREATE TABLE t1 (
id INT UNIQUE KEY
) ENGINE='NDB';
CREATE TABLE t2 (
id INT PRIMARY KEY,
t1id INT
) ENGINE='NDB';
ALTER TABLE t2
ADD CONSTRAINT t2t1 FOREIGN KEY (t1id) REFERENCES t1 (id)
ON DELETE CASCADE ON UPDATE CASCADE;
Works just fine.
Is there any rule that says "with the NDB storage engine you cannot reference a primary key column in a foreign key constraint" or "with NDB you have to reference UNIQUE KEYS in foreign key constraints"?
To make things even stranger:
If you replace the definition of t1 by
CREATE TABLE t1 (
id INT UNIQUE KEY NOT NULL
) ENGINE='NDB';
you get the same error.
I'm thinking that PRIMARY KEY implies NOT NULL and that the problem lies not with the former but with the latter.
From what I gathered from MySQL site and Dev blogs:
An important difference to note with the Foreign Key implementation in
InnoDB is that MySQL Cluster does not support the updating of Primary
Keys from within the Data Nodes themselves - instead the UPDATE is
emulated with a DELETE followed by an INSERT operation. Therefore an
UPDATE operation will return an error if the parent reference is using
a Primary Key, unless using CASCADE action, in which case the delete
operation will result in the corresponding rows in the child table
being deleted. The Engineering team plans to change this behavior in a
subsequent preview release.
Foreign Keys in MySQL Cluster
New MySQL Cluster 7.3 Previews
MySQL Cluster 7.3 Labs Release – Foreign Keys Are In!
Recent MySQL Cluster posts
Support for such operation is not yet confirmed.
Related
Working on adding testing to an existing project that uses Flyway. The tables are in Versioned flyway files, so they can't change, but trying to figure out what the cause of this basic use-case is.
CREATE TABLE table1
(
id LONG PRIMARY KEY AUTO_INCREMENT
);
CREATE TABLE table2
(
id LONG PRIMARY KEY AUTO_INCREMENT
);
CREATE TABLE table3
(
id LONG PRIMARY KEY AUTO_INCREMENT,
t1_id LONG,
t2_id LONG
);
ALTER TABLE table3
ADD FOREIGN KEY (t1_id) REFERENCES table1 (id),
ADD FOREIGN KEY (t2_id) REFERENCES table2 (id);
Causes:
SQL State : 42000
Error Code : 42000
Message : Syntax error in SQL statement "ALTER TABLE TABLE3
ADD FOREIGN KEY (T1_ID) REFERENCES TABLE1 (ID),[*]
ADD FOREIGN KEY (T2_ID) REFERENCES TABLE2 (ID)"; SQL statement:
ALTER TABLE table3
ADD FOREIGN KEY (t1_id) REFERENCES table1 (id),
ADD FOREIGN KEY (t2_id) REFERENCES table2 (id) [42000-200]
Location : db/migration/V1_0__init.sql ...V1_0__init.sql)
Line : 18
Statement : ALTER TABLE table3
ADD FOREIGN KEY (t1_id) REFERENCES table1 (id),
ADD FOREIGN KEY (t2_id) REFERENCES table2 (id)
In testing, the following two scenarios are successful though..
-- Only 1 foreign key
ALTER TABLE table3
ADD FOREIGN KEY (t1_id) REFERENCES table1 (id);
-- Inlined foreign keys in table creation
CREATE TABLE table3
(
id LONG PRIMARY KEY AUTO_INCREMENT,
t1_id LONG,
t2_id LONG,
FOREIGN KEY (t1_id) REFERENCES table1 (id),
FOREIGN KEY (t2_id) REFERENCES table2 (id)
);
Is there a limitation in H2 to add multiple foreign keys at the same time?
It's not a limitation of H2. In the SQL Standard you can't define multiple constraints at once in the ALTER TABLE statement, you can define them all at once only in the definition of the table. If they weren't already defined in the CREATE TABLE command, you need to use two separate ALTER TABLE commands:
ALTER TABLE table3
ADD FOREIGN KEY (t1_id) REFERENCES table1 (id);
ALTER TABLE table3
ADD FOREIGN KEY (t2_id) REFERENCES table2 (id)
Some databases, such as MySQL, have their own vendor-specific syntax, but such syntax is not compatible with other databases, including the H2 (even in MySQL compatibility mode).
Some how, my database has gotten into a bad state. I previously had a table named live_stream. When I tried to drop a foreign key constraint, I got an error that mariadb could not rename #sql-26_e7a to live_stream. Now when I try to run the following statement, I get this error.
Can't create table live_stream (errno: 150 "Foreign key constraint is incorrectly formed")
CREATE TABLE live_stream
(idbigint(20) NOT NULL PRIMARY KEY);
As you can see I don't have any foreign key constraints in the definition. If I try the exact same definition with a different table name, it works. If I try to drop the table, mariadb complains that live_stream doesn't exist. Its like the table or foreign key are stuck in a transaction or something like that.
I am using galara with maria db 10.3.
UPDATE
I believe the problem was introduced when a foreign key and unique index were given the same name. I recreated the scenario, and when I try to drop the index, mariadb prevents it.
* UPDATE 2 *
Here is the output of SHOW ENGINE INNODB STATUS;
* UPDATE3 *
Here are the steps to reproduce.
create table tb1
(
id bigint null,
constraint tb1_pk
primary key (id)
);
create table tb2
(
id bigint null,
tb1_id bigint null,
constraint tb2_pk
primary key (id),
constraint tb2_tb1_id_fk
foreign key (tb1_id) references tb1 (id)
);
ALTER TABLE tb2 ADD CONSTRAINT tb2_tb1_id_fk UNIQUE (tb1_id, tb1_id);
drop index tb2_tb1_id_fk on tb2;
The problem is that the unique constraint has the same name as the foreign key and references the same column twice.
I would like to create a table that has multiple foreign keys to multiple different tables (as the relationship is many to many).
#creating t1
CREATE TABLE t1
(ID INT AUTO_INCREMENT primary key,
x1 VARCHAR(50)
);
#Creating t2
CREATE TABLE t2
(v1 VARCHAR(50),
v2 VARCHAR(50),
primary key (v1, v2)
);
#creating attended table
CREATE TABLE t3
(ID INT,
v1 VARCHAR(50),
v2 VARCHAR(50),
primary key (ID, v1, v2 ),
foreign key(v1) references t2(v1),
foreign key(v2) references t2(v2),
foreign key(ID) references t1(ID)
);
Above is my code. I get no errors for creating t1 and t2. However, I get the following code when I try to create t3:
ERROR 1215 (HY000): Cannot add foreign key constraint
The foreign key is the complete key of the other table - you can not only use half of it as FK.
t2 has a combined primary key. when referencing a fk in t3 you need both.
See Why use multiple columns as primary keys (composite primary key)
To create a complex FK see SQL Server: adding foreign key on multiple columns
or for MySql see Multiple-column foreign key in MySQL?
Here is the exact SQL I attempt to execute (using SQLYog as a MySQL client on Windows):
DROP TABLE IF EXISTS `test`;
CREATE TABLE `test` (
`id` INT (11) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`)
) ENGINE = INNODB ;
DROP TABLE IF EXISTS `temp`;
CREATE TEMPORARY TABLE `temp` (
dish_id INT (11) NOT NULL,
user_id INT (11) NOT NULL,
UNIQUE KEY (dish_id, user_id),
FOREIGN KEY `test` (dish_id) REFERENCES test (id)
) ENGINE = INNODB ;
Here is the exact error received upon the attempt to create temp:
Error Code: 1215
Cannot add foreign key constraint
It looks to me like everything is in order - the data type and signed-ness of the two related keys is the same; the names appear to be kosher; what is going on?
What am I doing wrong? Why is the foreign key constraint failing to be created?
It's because you're trying to add a foreign key constraint to a temporary table.
From the manual:
Foreign key relationships involve a parent table that holds the
central data values, and a child table with identical values pointing
back to its parent. The FOREIGN KEY clause is specified in the child
table. The parent and child tables must use the same storage engine.
They must not be TEMPORARY tables.
http://dev.mysql.com/doc/refman/5.5/en/create-table-foreign-keys.html
EDIT:
Try it with a permanent table. It works.
DROP TABLE IF EXISTS `test`;
CREATE TABLE `test` (
`id` INT (11) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`)
) ENGINE = INNODB ;
DROP TABLE IF EXISTS `temp`;
CREATE TABLE `temp` (
dish_id INT (11) NOT NULL,
user_id INT (11) NOT NULL,
UNIQUE KEY (dish_id, user_id),
FOREIGN KEY `test` (dish_id) REFERENCES test (id)
) ENGINE = INNODB ;
I use MySQL Workbench to design my database and then to export the SQL CREATE script. But when I run this script to create the database, I get an error - errno: 121.
It turns out that MySQL Workbench gives two constraints the same name, because both constraints use the same key (I have a table with primary key 'roleID' and I reference this key in two other tables).
Is there any way how I can rename the constraint directly in the designer, so when I forward engineer the SQL CREATE script, it will give no errors?
I tried double click the relation in the designer and give it a new caption, but it still generates the script with the original name.
Part of the generated script which creates the error:
CREATE TABLE IF NOT EXISTS users.roles (
roleID INT NOT NULL AUTO_INCREMENT ,
...
PRIMARY KEY (roleID) ,
...);
CREATE TABLE IF NOT EXISTS users.userRoles (
...
roleID INT NOT NULL ,
...
CONSTRAINT roleID
FOREIGN KEY (roleID )
REFERENCES users.roles (roleID ));
CREATE TABLE IF NOT EXISTS users.resourcePrivileges (
roleID INT NOT NULL ,
...
CONSTRAINT roleID
FOREIGN KEY (roleID )
REFERENCES users.roles (roleID ));
Not sure how you ended up with that. I took MySQL WorkBench for a spin, created two tables with a FK and it created
-- -----------------------------------------------------
-- Table `mydb`.`users`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `mydb`.`users` (
`idusers` INT NULL ,
PRIMARY KEY (`idusers`) )
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `mydb`.`usersRoles`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `mydb`.`usersRoles` (
`users_idusers` INT NOT NULL ,
PRIMARY KEY (`users_idusers`) ,
CONSTRAINT `fk_usersRoles_users`
FOREIGN KEY (`users_idusers` )
REFERENCES `mydb`.`users` (`idusers` )
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
Notice that the constraint has a unique name 'fk_usersRoles_users' that would not get duplicated since it uses table names.
Just for fun I added another relationship between the same tables and by default I get
-- -----------------------------------------------------
-- Table `mydb`.`usersRoles`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `mydb`.`usersRoles` (
`users_idusers` INT NOT NULL ,
`users_idusers1` INT NOT NULL ,
PRIMARY KEY (`users_idusers`, `users_idusers1`) ,
INDEX `fk_usersRoles_users1` (`users_idusers1` ASC) ,
CONSTRAINT `fk_usersRoles_users`
FOREIGN KEY (`users_idusers` )
REFERENCES `mydb`.`users` (`idusers` )
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `fk_usersRoles_users1`
FOREIGN KEY (`users_idusers1` )
REFERENCES `mydb`.`users` (`idusers` )
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
Which again is a non problem (all of the above is auto generated - I have only set the table names, primary key on referenced table and added two 1:N relationships)
NOTES: Version 5.2.30.
EDIT
Maybe something happened with your preferences. The default name for the fk constraints is defined on the model tab.
Error 121 is due to constraint name duplication.
Generally when generating your SQL script with MYSQL forward engineering export option, to resolve the issue we need to just ensure that the "Foreign Key Names" are unique in SQL script/ schema.
When you set a constraints for Foreign keys, will not assign different name that referring same primary key of some table. So, what am trying to say is that check all your index names in all the generated scripts if there any duplication. Rename to some other. Then you can proceed...