I'm trying to create relationships in MySQL using forein keys. Everytime I successfully create the forien key, but when I describe the table, the key is considered "MUL". After inserting some records into the parent table, I get null values in the child. I've been researching this for hours and have come up empty handed. I even checked the innodb status and have no foreign key error reports. I'm not entirely sure why I'm getting null values, but I'm assuming its because of the "MUL" key value. Can someone confirm this and try and help me out?
create table employee
( id int
, first varchar(128)
, last varchar(128)
, primary key(id)
) engine=innodb;
create table borrow
(ref auto_increment
, empID int
, book varchar(128)
, primary key(ref)
) engine=innodb;
alter table borrow add constraint fk_borrow
foreign key (empID) references employee(id);
insert into borrow (empID, book) values (1,'mike');
The 'MUL' just means that it's not a unique index (i.e. duplicate values are allowed for the KEY). (If it were a unique index, the Key column would show 'UNI'). The FOREIGN KEY constraint doesn't have anything to do with the uniqueness of the foreign key column... it normally is non-unique... a parent can usually have zero, one or more children.
The FOREIGN KEY constraint does not disallow NULL values in the child table. Only a NOT NULL constraint (or a trigger) will do that for you. It's perfectly reasonable for a row in a child table to be an orphan, to not be related to a parent.
When you do the INSERT to the child table, you need to provide a non-NULL value for the foreign key column, if you want that row to reference a row in the parent table.
A foreign key can be defined with an ON DELETE SET NULL clause, but that would only be effective if you were to later delete a parent row that had children related to it. In that case, the child rows would have their foreign key column values set to NULL when the parent row is removed.
Mike said: I'm concerned that the child's foreign key is not getting populated by the parent.
The parent is not responsible for populating the foreign key column of the child. There's an option to have the child's foreign key value updated automatically when the parent's id value is changed... preserving the relationship: ON UPDATE CASCADE. But other than the actions performed by an ON UPDATE or ON DELETE clause, the parent has no responsibility of maintaining the values in a child table.
Mike asked: So how would I get the child's column to be populated from the parent?
You wouldn't. You would first locate (or insert) the row to the parent table. You would then preserve the value of the id column (or the values of whatever columns make up the PRIMARY KEY), and then use that same value for the foreign key column on the child row, when you insert a child row(s).
An error is returned when you set a foreign key to an arbitrary value (a value that does not match an existing PRIMARY KEY value in the parent table. That's the expected behavior.
If you are inserting the child row before the parent, you will need to leave the foreign key column as NULL, and then after you know the id value of the parent, you would then update the child row to set the foreign key column.
create table employee
( id int
, first varchar(128)
, last varchar(128)
, primary key(id) ) engine=innodb;
create table borrow
(ref auto_increment
, empID int
, book varchar(128)
, primary key(ref) ) engine=innodb;
alter table borrow add constraint fk_borrow
foreign key (empID) references employee(id);
insert into employee (id, first, last) values (1, 'foo', 'bar');
insert into borrow (empID, book) values (1,'mike');
insert into borrow (empID, book) values (1,'mulligan');
The two rows added to the borrow table are related to the row in employee, by virtue of the value in the foreign key column (empID) being set to a value that matches an id value in the employee table.
Related
I'm currently trying to add a new entry in a table. In this table I've a constraint to my users table (the user id). In some cases my user id can be not set yet. In the case it's empty, I'm getting an error:
Cannot add or update a child row: a foreign key constraint fails
This is how I setup my constraint:
So is there a way to insert an empty value to a constraint field? If no, what would be the best solution instead of removing the constraint?
So is there a way to insert an empty value to a constraint field?
Yes, there is. As long as the column controlled by the foreign key is not defined as NOT NULL, you can insert a NULL value into it, as explain in the manual. What is not allowed is to insert a non-NULL value that does not exists in the parent table (this includes the empty string!).
MySQL essentially implements the semantics defined by MATCH SIMPLE, which permit a foreign key to be all or partially NULL. In that case, the (child table) row containing such a foreign key is permitted to be inserted, and does not match any row in the referenced (parent) table.
Consider this demo on DB Fiddlde:
-- parent table
create table parent (id int primary key);
-- child table
create table child (
id int primary key,
parent_id int null, -- allow `NULL` values
constraint parent_id_fk foreign key(parent_id) references parent(id)
);
-- create a parent record
insert into parent(id) values(1);
-- insert a child record that references the parent: ok
insert into child(id, parent_id) values(1, 1);
-- insert a child record with a NULL parent_id : ok
insert into child(id, parent_id) values(2, NULL);
-- insert a child record with a (non-NULL) unknown parent_id
insert into child(id, parent_id) values(3, 2);
-- Error: Cannot add or update a child row: a foreign key constraint fails
I have following problem:
This is my code in MySQL:
create table fremd(
id int primary key,
name varchar(20),
foreign key(id) references mensch(id) on delete set null
);
id is the primary key of this table but also a foreign key which is referencing to the primary key of table mensch. The problem is the on delete set null statement. When I use cascade instead of set null it works. But with set null it doesnt work. What can i do?
This is the error message:
08:39:00 Error Code: 1215. Cannot add foreign key constraint 2.609 sec
You have two conflicting declarations in your CREATE TABLE:
id int primary key
This basically means that id is Primary Key. Now, a Primary key basically fulfills following two constraints:
It will be Unique. So, no two rows cannot have same value for id.
It will be NOT NULL. So, it can never be set as NULL.
On the other hand, your Foreign key definition states:
foreign key(id) references mensch(id) on delete set null
ON DELETE SET NULL basically means that when the parent table id value is deleted, the child table (this table's) id value is set to NULL. This directly conflicts with the Primary Key declaration, which stops it from becoming NULL.
That is why your foreign key cannot be defined. You can now use any of the following options to resolve this. But these options will have to be carefully determined based on your business logic:
Make id UNIQUE key instead of Primary Key. This will ensure that it remains a Unique value, as well as NULL can be used in it.
Change Foreign Key's ON DELETE behvaiour to something else, like, CASCADE (this will delete the child table row, when parent table row is deleted), or, RESTRICT (this will block the deletion from parent table).
I have two MySQL tables where the primary relationship between the two is one-to-many. I also need a one-to-one relationship in the parent_table with the ID for the primary record from the child_table. You can kind of think of it as like a dad having lots of kids but having one kid that's his favorite ;P. Is it possible to setup a DB constraint such that a parent can have the ID of a child only if that child is a child of the parent?
parent_table (One)
id: Primary Key
primary_child_id: {ID from child table}
child_table (Many)
id: Primary Key
parent_table: {ID from parent table}
EDIT: The primary child is optional and child records will only be created for an already existing parent. The child_table can certainly be created after the parent_table.
Yes, it's possible, but it's tricky.
CREATE TABLE parent_table (
id INT PRIMARY KEY,
primary_child_id INT,
FOREIGN KEY (primary_child_id) REFERENCES child_table(id)
);
CREATE TABLE child_table (
id INT PRIMARY KEY,
parent_id INT NOT NULL,
FOREIGN KEY (parent_id) REFERENCES parent_table(id)
);
This is a circular reference, so you end up having a chicken-and-egg problem.
I resolve this by making the parent_table.primary_child_id a NULLABLE column, so you can create a parent row even before there are any child rows to reference. If you use NULL in the foreign key column on a given row, it's not a violation of the constraint.
The other tricky part is defining the tables in a circular reference relationship, when creating them as new tables. So you have to leave out one or the other constraint definition until both tables are defined, and then ALTER TABLE to add the missing constraint.
CREATE TABLE parent_table (
id INT PRIMARY KEY,
primary_child_id INT
);
CREATE TABLE child_table (
id INT PRIMARY KEY,
parent_id INT NOT NULL,
FOREIGN KEY (parent_id) REFERENCES parent_table(id)
);
ALTER TABLE parent_TABLE
ADD FOREIGN KEY (primary_child_id) REFERENCES child_table(id);
the parent [shouldn't be allowed to] have a favorite child that isn't his.
Okay, if you need the parent to reference only child records that reference itself:
ALTER TABLE child_table
ADD UNIQUE KEY (parent_id, id);
ALTER TABLE parent_TABLE
ADD FOREIGN KEY (id, primary_child_id) REFERENCES child_table(parent_id, id);
If you create the index in the child table before creating the foreign key, then the foreign key can use that index instead of creating a redundant index.
If I'm understanding correctly, a trigger which raises a SIGNAL should work:
DELIMITER $$
CREATE TRIGGER parent_child BEFORE INSERT ON parent_table
FOR EACH ROW
BEGIN
IF NOT EXISTS (SELECT 1 FROM child_table WHERE id = new.id)
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'Constraint failed';
ENF IF;
END;
$$
I'm not sure how you're choosing which table should get a record first when each depends on the other. So instead of this trigger you might prefer to write a stored procedure to create the "primary" relationship and validate it also with a SIGNAL.
Yes. You want the child's ID changes/deletions to cascade up to the parent's "favorite child" field, and the parent's ID changes/deletions to cascade down to all its children.
Your parent table should have id and favchild, where id is its primary key index. You would then make a foreign key for favchild that references the child table's primary key.
On the child table, you would make a parent field with a foreign key that references the parent table's id. Then you can have many children with one parent, and one child is the parent's favorite.
However, in order to do this, you need to disable foreign key constraints when you create the parent, because you will need to create at least one child at the same time.
Edit
If the parent must make sure favchild is actually a child: Since the parent row is added first, it would only be updated with favchild by some application logic. In which case you can do the check during that update. The only constraint from that point on would be if favchild were to change parents. So for that your parent table could have two extra columns instead of one: favchild_id and favchild_parent_id. Make those a combined index, with a combined foreign key that references the two columns of the child. ON UPDATE SET NULL. The only drawback here is if the child's ID were to change, it would also be nulled instead of cascaded to the parent.
I'm trying to insert this code into my Albums table on my MySQL database
INSERT INTO `Albums` (`Albumid`, `Name`, `Numberoftracks`, `Artistid`, ]
`Genre`) VALUES (1, "Innuendo", 12, "Queen", "Rock");
But every time I try to I keep getting this error.
1452 - Cannot add or update a child row: a foreign key constraint fails
(`b4014107_db1/Albums`, CONSTRAINT `Albums_ibfk_1` FOREIGN KEY (`Artistid`)
REFERENCES `Artist` (`Artistid`))
I know it's something to do with my foreign key within the table, but I need to manually enter the foreign key because it's not auto-incremented.
Here's the tables code.
CREATE TABLE `Albums` ( `Albumid` int(6) NOT NULL, `Name` varchar(50) NOT
NULL, `Numberoftracks` int(11) NOT NULL, `Artistid` int(6) NOT NULL,
`Genre` varchar(50) NOT NULL, PRIMARY KEY (`Albumid`), KEY `Artistid`
(`Artistid`), CONSTRAINT `Albums_ibfk_1` FOREIGN KEY (`Artistid`)
REFERENCES `Artist` (`Artistid`)) ENGINE=InnoDB DEFAULT CHARSET=latin1
How do I fix this? I need to input data into the table.
artistid is a foreign key in the table Albums. Parent child relationship error comes when you try to insert a foreign key in child table which is not present in the parent table. artistid is not present in your Artist table.
Also, to add the the datatype of artistid is also different.
Taken from mysql docs
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.
It will reject any INSERT or UPDATE operation that attempts to create
a foreign key value in a child table if there is no a matching
candidate key value in the parent table.
To remove your error, insert the Queens artist in your Artist table first and then you can insert it into Albums table. Also correct the datatype of column artistid.
Using foreign keys doesn't mean any implicit auto-incrementation. A foreign key in a table means that a record must already exist in another.
see http://dev.mysql.com/doc/refman/5.5/en/create-table-foreign-keys.html (change version in the url regarding your needs)
Otherwise, make a trigger if you want the artist to be dynamically created.
Hope it'll clarify.
I have two parent tables, BusinessGroup and SocialGroup, and one child table, Members. A Member can belong to either parent, but not both.
As far as I can see, there are two options for constructing the child table.
Opt 1: Include a field for ParentType, and another for ParentID. The ParentType would be an enum (Business, Social) and the ParentID would be the PK from the respective parent table.
Opt 2: Include a field for BusinessGroupID, and another for SocialGroupID. In this case, the fields would need to be nullable, and only one could contain a value.
Any ideas on which approach is best?
I tried option 1 in MySQL, and created two foreign keys from the child back to the parents. I ran into trouble when inserting values though, since MySQL was expecting a corresponding value in BOTH parent tables.
As a supplementary question: how do things change if I have a larger number of parents, e.g. 6?
Thanks!
CREATE TABLE Group (
GroupID integer NOT NULL
, Name varchar(18)
, Description varchar(18)
, GroupType varchar(4) NOT NULL
-- all columns common to any group type
);
ALTER TABLE Group ADD CONSTRAINT pk_Group PRIMARY KEY (GroupID) ;
CREATE TABLE BusinessGroup (
GroupID integer NOT NULL
-- all columns specific to business groups
);
ALTER TABLE BusinessGroup
ADD CONSTRAINT pk_BusinessGroup PRIMARY KEY (GroupID)
, ADD CONSTRAINT fk1_BusinessGroup FOREIGN KEY (GroupID) REFERENCES Group(GroupID) ;
CREATE TABLE SocialGroup (
GroupID integer NOT NULL
-- all columns specific to social groups
);
ALTER TABLE SocialGroup
ADD CONSTRAINT pk_SocialGroup PRIMARY KEY (GroupID)
, ADD CONSTRAINT fk1_SocialGroup FOREIGN KEY (GroupID) REFERENCES Group(GroupID) ;
CREATE TABLE Person (
PersonID integer NOT NULL
, GroupID integer NOT NULL
);
ALTER TABLE Person
ADD CONSTRAINT pk_Person PRIMARY KEY (PersonID)
, ADD CONSTRAINT fk1_Person FOREIGN KEY (GroupID) REFERENCES Group(GroupID) ;
"parent tables" is probably a misnomer - in the relational model I'd flip your relationship. e.g. make members the master records table, and a join table that allows 1-1 mapping, so have a PK of member_id or whatever the right field is, and map to the FK in either BusinessGroup or SocialGroup.