insert first data into a recursive sql table - mysql

I have the following table:
Create Table if not exists Categories(
category_id int (10) primary key NOT NULL AUTO_INCREMENT,
category_name varchar (20) NOT NULL,
parent_category_id int (10) NOT NULL,
FOREIGN KEY (parent_category_id) REFERENCES Categories(category_id) ON DELETE CASCADE)
The table is holding every category I have on my site - and each category have a parent category (for example 'computer' is the parent category of 'programming')
I have a few top categories which don't have any parent category => parent_category_id =0
My question is how to insert the data for the top categories.
when i'm trying to do:
INSERT INTO `databaseproject`.`categories` (`category_id` ,`category_name` ,`parent_category_id`)
VALUES (NULL , 'computers', '0')
I'm getting the error:
#1452 - Cannot add or update a child row: a foreign key constraint fails (`databaseproject`.`categories`, CONSTRAINT `categories_ibfk_1`
FOREIGN KEY (`parent_category_id`) REFERENCES `categories` (`category_id`) ON DELETE CASCADE)
what can I do to insert those categories?

Make parent_category_id nullable, and parent categories have a null parent_category_id, or add a root row with id 0.

You have two problems. First, category_id is an auto_increment field, meaning the database will create a value for you when you insert a new row, so you don't need to provide it. You certainly can't set it to null, since you have specifically said it can't be null, which is absolutely what you want for an auto-incrementing id field. Just change your insert to:
INSERT INTO 'databaseproject'.'categories' ('category_name' ,'parent_category_id')
VALUES ('computers', '0')
But you still have another problem. parent_category_id has to refer to a valid record in the categories table because of the constraint you created. You can solve this problem by allowing the field to be null (get rid of the "NOT NULL" when creating the parent_category_id), and using null instead of zero to indicate this is a top level record.

Related

Can't insert values into table, foreign key constraint keeps failing

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.

MySQL foreign keys doesn't cause child table to populate

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.

Exact Meaning of MySQL's Foreign Key 'on delete restrict' Clause

I have two MySQL tables: collections and privacy_level.
I define them with a foreign key relationship as such:
CREATE TABLE collections (
coll_id smallint NOT NULL AUTO_INCREMENT UNSIGNED,
name varchar(30) NOT NULL,
privacy tinyint NOT NULL UNSIGNED DEFAULT '0',
PRIMARY KEY(coll_id),
INDEX(privacy),
FOREIGN KEY fk_priv (privacy) REFERENCES privacy_level (level) ON UPDATE CASCADE ON DELETE RESTRICT
) ENGINE=InnoDB;
CREATE TABLE privacy_level (
level tinyint NOT NULL UNSIGNED,
name varchar(20) NOT NULL,
PRIMARY KEY (level)
) ENGINE InnoDB;
My question is about the ON DELETE RESTRICT clause and I couldn't derive the answer from the online manual or a google search.
Does this mean that I can never delete a row from privacy_level?
Or, does it mean that I can't delete a row from privacy_level if a row from collections.privacy has a value that is the same as a value in privacy_level.level?
That is, if privacy_level has level = 2, name = 'top secret' but no entry in collections.Privacy has privacy = 2, can I delete the level = 2, name = 'top secret' entry? Or is it forbidden on a column wide basis?
Thanks for any insight.
ON DELETE RESTRICT means you can't delete a given parent row if a child row exists that references the value for that parent row. If the parent row has no referencing child rows, then you can delete that parent row.
ON DELETE RESTRICT is pretty much superfluous syntax, because this is the default behavior for a foreign key anyway.
Also you can use ON DELETE CASCADE, that means when you delete the parent all the children will be removed automatically, this is useful when you have a table associated with another that contains some parameters or settings.

Best MySQL Table Structure: 2 Parents, 1 Child

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.

Is it possible to have a mysql table accept a null value for a primary_key column referencing a different table?

I have a table that has a column which holds the id of a row in another table. However, when table A is being populated, table B may or may not have a row ready for table A.
My question is, is it possible to have mysql prevent an invalid value from being entered but be ok with a NULL? or does a foreign key necessitate a valid related value?
So... what I'm looking for (in pseudo code) is this:
Table "person" id | name
Table "people" id | group_name | person_id (foreign key id from table person)
insert into person (1, 'joe');
insert into people (1, 'foo', 1)//kosher
insert into people (1, 'foo', NULL)//also kosher
insert into people(1, 'foo', 7)// should fail since there is no id 7 in the person table.
The reason I need this is that I'm having a chicken and egg issue where it makes perfect sense for the rows in the people table to be created before hand (in this example, I'm creating the groups and would like them to pre-exist the people who join them). And I realize that THIS example is silly and I would just put the group id in the person table rather than vice-versa, but in my real-world problem that is not workable.
Just curious if I need to allow any and all values in order to make this work, or if there's some way to allow for null.
If you set the column as nullable then it can contain NULL even if it is a foreign key referencing a column in another table.
Foreign keys can be null.
When the row in the referenced table is entered you'll have to UPDATE that row to point to it.
You set a foreign key column to accept nulls by setting the optionality of the column to NULL:
DROP TABLE IF EXISTS `example`.`tableb`;
CREATE TABLE `example`.`tableb` (
`id` int(10) unsigned NOT NULL auto_increment,
`person_id` int(10) unsigned default NULL, -- notice, !say "NOT NULL" like id
PRIMARY KEY (`id`),
CONSTRAINT `FK_tableb_1` FOREIGN KEY (`person_id`) REFERENCES `tablea` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
That said, tablea has to have at least one record in it before you attempt to insert a null value into the tableb reference column. Otherwise, MySQL will throw an error (for me anyways, on 4.1).