Below is the simplified picture of the relationships I have in my DB:
create table attribute (id int auto_increment, primary key (id));
create table state_sample (id int auto_increment, primary key(id));
create table state_sample_attribute (
state_sample_id int,
attribute_id int,
primary key(state_sample_id, attribute_id),
foreign key (state_sample_id) references state_sample(id) on update cascade,
foreign key (attribute_id) references attribute(id) on update cascade
);
create table note (
id int auto_increment,
state_sample_id int,
attribute_id int,
primary key(id),
foreign key (state_sample_id) references state_sample(id) on update cascade,
foreign key (state_sample_id, attribute_id)
references state_sample_attribute(state_sample_id, attribute_id) on update cascade
);
insert into attribute values (1);
insert into state_sample values (1);
insert into state_sample_attribute values (1, 1);
insert into note values (1, 1, 1);
Whenever I try to update the ss table, it fails:
update state_sample set id = 2;
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`demotemplate`.`note`, CONSTRAINT `note_ibfk_1` FOREIGN KEY (`ss_id`) REFERENCES `ss` (`id`) ON UPDATE CASCADE)
As far as I understand, this is what happens:
It tries to set state_sample.id = 2.
It sees the cascade to note and tries to update note.state_sample_id.
However, note.state_sample_id is also involved in the foreign key to to state_sample_attribute(state_sample_id, attribute_id), so it goes to check whether that's still valid.
As state_sample_attribute.state_sample_id has not yet been updated, the constraint fails.
Is my assumption correct? And if so, is there a way to work this around?
Give the ssa table its own id primary key, and use that in the foreign key in notes, rather than referencing the ss_id and a_id columns.
create table ssa (
id int auto_increment,
ss_id int,
a_id int,
primary key (id),
unique key (ss_id, a_id),
foreign key (ss_id) references ss(id) on update cascade,
foreign key (a_id) references a(id) on update cascade);
create table note (
id int auto_increment,
ss_id int,
ssa_id int,
primary key(id),
foreign key (ss_id) references ss(id) on update cascade,
foreign key (ssa_id) references ssa(id) on update cascade);
Now you don't have the redundant dependency.
It's also not clear that note needs ss_id at all, since it's redundant with the related ssa row.
Try
DISABLE KEYS
or
SET FOREIGN_KEY_CHECKS=0;
make sure to turn it on
SET FOREIGN_KEY_CHECKS=1;
after.
What solved it in the end is dropping the extra FK:
alter table note drop foreign key (state_sample_id) references state_sample(id);
Related
I've created two tables to do mappings between users. First for users and second for user-mappings. Deletion of users work well, but if I try to update the user id the foreign key constraints from the mapping table fail (without a helpful error output).
CREATE TABLE user (
id INT NOT NULL AUTO_INCREMENT,
name VARCHAR(55),
PRIMARY KEY (`id`)
);
CREATE TABLE user_map (
map_id INT NOT NULL AUTO_INCREMENT,
user_a INT,
user_b INT,
PRIMARY KEY (`map_id`),
UNIQUE KEY `one_way` (`user_a`,`user_b`),
UNIQUE KEY `other_way` (`user_b`,`user_a`),
CONSTRAINT `acc_connections_ibfk_1` FOREIGN KEY (`user_a`) REFERENCES `user` (`id`) ON UPDATE CASCADE ON DELETE CASCADE,
CONSTRAINT `acc_connections_ibfk_2` FOREIGN KEY (`user_b`) REFERENCES `user` (`id`) ON UPDATE CASCADE ON DELETE CASCADE
)
Example Data:
INSERT INTO user (name) VALUES ("User A");
INSERT INTO user_map (user_a,user_b) VALUES (1,1);
If I try to update the user id afterwards I get the following error:
Cannot add or update a child row: a foreign key constraint fails
(`test_db`.`user_map`, CONSTRAINT `user_map_ibfk_2`
FOREIGN KEY (`user_b`) REFERENCES `user` (`id`) ON DELETE CASCADE ON UPDATE CASCADE)
DB Fiddle (Demo)
Interestingly deleting the parent row (user table) succeeds without an error.
What am I doing wrong? I see no reason why this should fail.
I don't know if this is a bug or intended behavior.
As a workaround, if your version of MySql is 8.0.13+, which supports Functional Key Parts, you can use 1 UNIQUE KEY (to check the uniqueness of the combination of the 2 columns) instead of the 2 keys and the UPDATE statement will work:
CREATE TABLE IF NOT EXISTS user_map (
map_id INT NOT NULL AUTO_INCREMENT,
user_a INT,
user_b INT,
PRIMARY KEY (`map_id`),
UNIQUE KEY unk_users((LEAST(`user_a`,`user_b`)), (GREATEST(`user_a`,`user_b`))),
CONSTRAINT `acc_connections_ibfk_1` FOREIGN KEY (`user_a`) REFERENCES `user` (`id`) ON UPDATE CASCADE ON DELETE CASCADE,
CONSTRAINT `acc_connections_ibfk_2` FOREIGN KEY (`user_b`) REFERENCES `user` (`id`) ON UPDATE CASCADE ON DELETE CASCADE
);
See the demo.
I am doing on these two tables, which is accountinfo and userrecipeinfo
accountinfo
create table accountinfo
(
id int NOT NULL AUTO_INCREMENT,
username varchar(80),
password varchar(80),
name varchar(80),
primary key (id)
);
userrecipeinfo
create table userrecipeinfo
(
recipeid int NOT NULL AUTO_INCREMENT,
recipename varchar(80),
reciperating int,
recipephoto LONGTEXT,
primary key (recipeid),
foreign key (recipeid) references accountinfo(id)
);
However, when I try to insert one of the values
insert into userrecipeinfo (recipename, reciperating, recipephoto)
values ('tom yum', 4, 'https://www.cbronline.com/wp-content/uploads/2016/07/Trolling.jpg');
I get an error:
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (userinfo.userrecipeinfo, CONSTRAINT userrecipeinfo_ibfk_1 FOREIGN KEY (recipeid) REFERENCES accountinfo (id))
I would like to know what caused this error. Thanks!
You are violating the foreign key constraint. When a foreign key is added it must match a existing value in the reference table.
In your case userrecipeinfo.recipeid refers to accountinfo.id, so when you insert a row into userrecipeinfo, there must be a corresponding row in accountinfo which matches accountinfo.id = userrecipeinfo.recipeid.
You can try select * from accountinfo where id=4; to see whether there is a row whose id is 4.
Is it possible to have a foreign key (InnoDB) reference two possible tables?
If not, is there a workaround for this?
There are two different subjects that contain the same field (interface_id). A third table references this field.
An example being:
physical_interface ( id, name, etc )
virtual_interface ( id, name, etc )
usage ( interface_id, etc )
I had an idea of using a view, but came across this related to SQL server: Can I have a foreign key referencing a column in a view in SQL Server? so it seems you cannot use views in foreign keys.
The alternative, I suppose, would be storing all intefaces in one table but I feel that would be less organized.
Well, the answer is interesting. MySQL 5.6.14, my version, won't stop you from creating a foreign key relationship with 2 tables but that is a bad idea. Let me show you why.
Create 2 master tables: test1 and test3
create table test1 (field1 int, primary key (field1));
create table test3 (field1 int, primary key (field1));
Create a dependent table that will have FK relationship with field1 of both tables.
create table test2 (
field0 int,
field1 int,
constraint fk_test2_test1
foreign key (field1)
references test1 (field1),
constraint fk_test2_test3
foreign key (field1)
references test3 (field1)
);
Great. Now let's add some data and see the issue:
insert into test1 values (1);
insert into test3 values (3);
Master tables are done. Let's add data to dependent table.
insert into test2 values (100, 1);
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`test`.`test2`, CONSTRAINT `fk_test2_test3` FOREIGN KEY (`field1`) REFERENCES `test3` (`field1`))
insert into test2 values (100, 3);
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`test`.`test2`, CONSTRAINT `fk_test2_test1` FOREIGN KEY (`field1`) REFERENCES `test1` (`field1`))
insert into test2 values (100, 2);
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`test`.`test2`, CONSTRAINT `fk_test2_test1` FOREIGN KEY (`field1`) REFERENCES `test1` (`field1`))
So...don't do that.
Proposal
create table interface_type (
id int auto_increment,
type_name varchar(30),
primary key (id)
);
create table interface (
id int auto_increment,
interface_name varchar(30),
interface_type int,
primary key (id),
constraint fk_interface_type
foreign key (interface_type)
references interface_type (id)
);
create table `usage` (
id int auto_increment,
interface_id int,
primary key (id),
constraint fk_usage_interface
foreign key (interface_id)
references interface (id)
);
Now you can add as many types of interfaces in the interface_type table such as:
insert into interface_type (type_name) values ('physical'), ('virtual');
Then, add as many interfaces as you'd like in the interface table, and reference them in the usage table as needed.
Here's the basic gist of what I'm trying to do:
create table main(id char(1) primary key);
create table other (
id int primary key auto_increment,
main_id char(1),
key m (main_id),
constraint fk foreign key (main_id) references main(id)
);
insert into main(id) values('a');
insert into other(main_id) values('a');
update main inner join other on other.main_id=main.id
set main.id='b', other.main_id='b'
where main.id='a';
This results in a foreign key constraint failure. Is there any way to accomplish this without dropping the foreign keys (not really an option on my large production database)?
You can do this simply by temporarily setting foreign_key_checks=0 in your session:
set foreign_key_checks=0;
update main inner join other on other.main_id=main.id
set main.id='b', other.main_id='b'
where main.id='a';
Another option is to configure the foreign key with the ON UPDATE CASCADE option so that if the primary key is updated on the parent table it will cascade to the child table:
create table main(id char(1) primary key);
create table other (
id int primary key auto_increment,
main_id char(1),
key m (main_id),
constraint fk foreign key (main_id) references main(id) on update cascade
);
I have users, have offers, and a junction table users_offers.
Is there a setup I can carry out with foreign key relations that can ensure that junction data will be automatically deleted when I delete any users or offers?
Declare a referential action: ON DELETE CASCADE, for example:
CREATE TABLE user (
user_id int PRIMARY KEY
);
CREATE TABLE offer (
offer_id int PRIMARY KEY
);
CREATE TABLE user_offer (
user_id int,
offer_id int,
PRIMARY KEY (user_id, offer_id),
FOREIGN KEY (user_id) REFERENCES user (user_id) ON DELETE CASCADE,
FOREIGN KEY (user_id) REFERENCES offer (offer_id) ON DELETE CASCADE
);
[SQL Fiddle]
Interestingly enough, it seems that specifying referential action in "shorthand" foreign key syntax doesn't work (confirmed under MySQL 5.5.30, 5.6.6 m9). The following gets parsed, but when user is deleted, the corresponding user_offer doesn't get deleted:
CREATE TABLE user_offer (
user_id int REFERENCES user (user_id) ON DELETE CASCADE,
offer_id int REFERENCES offer (offer_id) ON DELETE CASCADE,
PRIMARY KEY (user_id, offer_id)
);
You can specify this within your model creation:
CREATE TABLE users_offers (user_id INT NOT NULL,
offer_id INT NOT NULL,
PRIMARY KEY (user_id, offer_id),
FOREIGN KEY (user_id) REFERENCES users(id)
ON DELETE CASCADE,
FOREIGN KEY (offer_id) REFERENCES offers(id)
ON DELETE CASCADE);
You can see a working example in this Fiddle.