MySQL add primary key after foreign key insert - mysql

I have two tables (A, B) with a foreign key from B to A.
So A is my parent table and B my child.
I now insert a row in B before the parent row exists in A. So I set the foreign key to an id I know parent A will have, but which is not existing right know. To achieve that I use the option 'SET foreign_key_checks = 0', which allows to set a foreign key in the child B without the existens of the key in the parent A.
My question is, what will happen, if I add the row in A with the missing primary key. Will the foreign key <-> primary key connection work and will it be as fast as normal? Or do I have to drop the fk key and rebuild it?
I use InnoDB and MySQL 5.5.
... and I know that is probably very bad practice...
Or short:
I have a parent and a child table, linked by a foreign key. I add the child first, what happens if I add the parent later?

My question is, what will happen, if I add the row in A with the
missing primary key. Will the foreign key <-> primary key connection
work and will it be as fast as normal? Or do I have to drop the fk key
and rebuild it?
If you will add missing record into parent table, the FK constraint will work as it should be. You will actually solve the data inconsistency.
There is no need to recreate FK.

I tried it myself by creating an example.
CREATE TABLE `parent` (
`idparent` int(11) NOT NULL,
PRIMARY KEY (`idparent`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CREATE TABLE `parent` (
`idparent` int(11) NOT NULL,
PRIMARY KEY (`idparent`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
SET foreign_key_checks = 0;
INSERT INTO child (idchild, parentid) VALUES (1,1),(2,2),(3,3),(4,4),(5,5);
SET foreign_key_checks = 1;
INSERT INTO parent (idparent) VALUES (1),(2),(3),(4),(5);
Next, I used explain to get an idea, if the index is used:
EXPLAIN SELECT * from parent p
join child c on c.parentid = p.idparent;
+----+-------------+-------+-------+-----------------+-----------------+---------+----------------------+------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+-----------------+-----------------+---------+----------------------+------+--------------------------+
| 1 | SIMPLE | p | index | PRIMARY | PRIMARY | 4 | NULL | 5 | Using index |
| 1 | SIMPLE | c | ref | fk_parentid_idx | fk_parentid_idx | 5 | remove_me.p.idparent | 1 | Using where; Using index |
+----+-------------+-------+-------+-----------------+-----------------+---------+----------------------+------+--------------------------+
So it looks like it uses the index, altough at first the foreign key was not set. Therefore, it should be at least speedwise no problem.

INSERT INTO `area` (
`area_id` PRIMARY KEY,
`area_name`,
`chemist_id`FOREIGN KEY
)
VALUES (
[value-1],
[value-2],
[value-3]
)

Related

MySQL: is primary key unique by default?

If I define a column as a primary key in MySQL, is it also unique key by default or do I need to also define it as unique key (in case I want it to be unique)?
I saw this question What is the difference b/w Primary Key and Unique Key that explain the difference between the two, but doesn't exactly answer my question.
Does PK is UK by default or I need to explicitly define it?
Primary key is always unique in every SQL. You dont have to explicitly define it as UNIQUE.
On a side note: You can only have onePrimary key in a table and it never allows null values. Also you can have only one primary key constraint in the table(as the point of creating a primary key is to uniquely identify the row in your table) but you can more than one unique key constraint in your table.
Example:
An employee details table having EmpID as Primary key and EmpPhoneNo as unique key.
Primary key is always unique by definition. Not only in MySQL.
So you don't need any additional unique key.
Note that composite keys may lead to confusion : indeed a primary key can be a composite key, and DESCRIBE will show all of the composite key components as primary keys :
> DESCRIBE foobar;
+----------------------+------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------------------+------------------+------+-----+---------+-------+
| column_A | int(10) unsigned | NO | PRI | NULL | |
| column_B | int(10) unsigned | NO | PRI | NULL | |
+----------------------+------------------+------+-----+---------+-------+
However SHOW CREATE TABLE will show the reality :
> SHOW CREATE TABLE foobar;
+--------+---------------------------…+
| Table | Create Table …|
+--------+---------------------------…+
| foobar | CREATE TABLE `foobar` (
`column_A` int(10) unsigned NOT NULL,
`column_B` int(10) unsigned NOT NULL,
PRIMARY KEY (`column_A`,`column_B`),
KEY `column_B` (`column_B`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
+--------+---------------------------…+

Referencing table with generated primary keys

I am trying to increase the constraint of my MySQL database schema adding foreign key constraint to each table.
Table 1: USERS
+---------+----------+-------------
| id | username | Other fields
+---------+----------+-------------
| 1 | John |
| 2 | Mark |
+---------+----------+-------------
id INT(11) UNSIGNED NOT NULL AUTO_INCREMENT
username` VARCHAR(50) NOT NULL
PRIMARY KEY (id)
Table 2: DISKS (This has a one to many relationship with USERS)
+---------+----------+-----------+-------------
| id | id_user | disk_name | Other fields
+---------+----------+-----------+-------------
| 1 | 1 | disk A |
| 2 | 2 | disk B |
+---------+----------+-----------+-------------
id INT(11) UNSIGNED NOT NULL AUTO_INCREMENT
id_user INT(11) NOT NULL,
PRIMARY KEY (id,id_user)
INDEX fk_disks_idx (id ASC)
CONSTRAINT fk_disks
FOREIGN KEY (id)
REFERENCES database.USERS (id)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
Table 3: FILES (This has a one to many relationship with DISKS)
+---------+----------+----------+-----------+-------------
| id | id_disk | id_user | file_name | Other fields
+---------+----------+----------+-----------+-------------
| 1 | 1 | 1 | |
| 2 | 2 | 2 | |
+---------+----------+----------+-----------+-------------
id INT(11) UNSIGNED NOT NULL AUTO_INCREMENT
id_user INT(11) NOT NULL
id_disk INT(11) NOT NULL
PRIMARY KEY (id,id_disk,id_user )
INDEX fk_files_idx (id ASC, id_user ASC)
CONSTRAINT fk_files
FOREIGN KEY (id_disk, id_user, id_user)
REFERENCES database.DISKS (id)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
Table 2: FILES_ON_NAS (This has a one to one relationship with FILES)
+-------+----------+----------+----------+-----------+-------------
| id | id_files | id_user | id_disk | file_name | Other fields
+-------+----------+----------+----------+-----------+-------------
| 1 | 1 | 1 | 1 | |
| 2 | 1 | 2 | 2 | |
+-------+----------+----------+----------+-----------+-------------
id INT(11) UNSIGNED NOT NULL AUTO_INCREMENT
id_files INT(11) NOT NULL,
id_user INT(11) NOT NULL,
id_disk INT(11) NOT NULL,
PRIMARY KEY (id,id_files,id_user,id_disk )
INDEX fk_files_on_nas_idx (id ASC)
CONSTRAINT fk_files_on_nas
FOREIGN KEY (id_files,id_user,id_disk)
REFERENCES database.FILES (id,id_user, id_disk)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
Question:
As you can see the more I reference table in cascade the more primary keys I get. How can I design the database to avoid the replication of primary keys and therefore data duplication as well? Should I delete the auto incremented key for each table? Is it a good practice?
Thanks
The ID of the disk is sufficient to uniquely identify a disk. So there's no reason to include the ID of the user into the disk's primary key. It would even be an extremely bad idea, because that means that if a disk's user changes, you would need to modify the primary key.
Same for a file. A file ID uniquely identifies a file. So there's no reason to add the disk ID into the primary key of a file.
I would strongly advise against deleting the auto-incremented keys.
However you don't need to make a new primary key everytime :
If you want that multiple users share one disk, just put a foreign key of id_disk in USERS
If you want that one user can have multiple disks, then put a foreign key of id_user in DISKS instead.
Only use primary keys like that when you face a Many-to-Many relationship. In this case, you need to create a new table to join both tables; with the primary keys of both tables as foreign keys making a coupled primary key like you did.
You might want to read a little about Database Normalization. In your case, i would make the surrogate key id the only primary key in the tables. Something like:
create table users (
id integer not null auto_increment,
username varchar(50),
...,
primary key (id)
);
create table disks (
id integer not null auto_increment,
user_id integer,
diskname varchar(50),
....,
primary key (id),
foreign key (user_id) references users (id)
);
For files you are going to have to answer the question: does file ownership depend on the file directly, or transitively on the disk ownership, or are the ownerships independent? A file owned by John on a disk owned by Jack? Seems ok to me, but your domain might have different rules. In that case, drop the user_id from the files table (otherwise your database won't be in Third normal form).
create table files (
id integer not null auto_increment,
disk_id integer,
user_id integer, -- you have to decide whether this is necessary
filename varchar(50),
....,
primary key (id),
foreign key (disk_id) references disks (id),
foreign key (user_id) references users (id)
);

PHP MySQL Delete parent and child rows

I have 1 MySQL Table. It looks like this:
+---------+-------------+--------+
| item_id | parent_id | Name |
+---------+-------------+--------+
| 1 | 0 | Home |
+---------+-------------+--------+
| 2 | 1 | Sub |
+---------+-------------+--------+
| 3 | 2 | SubSub |
+---------+-------------+--------+
If I DELETE item_id 1, I want to delete the rest of the sub also but how can I do it?
I have tried the Foreign Key but it works only if you have 2 tables??
I hope someone can help me in MySQL maybe PHP?
You can, most definitely, use self-referencing foreign keys with MySQL (you don't need multiple tables). However, for any kind of foreign key support, you need to use the InnoDB engine. And my guess is, that you are using the MyISAM engine.
With InnoDB you could create a table, similar to what you have already, including the self-referencing foreign key, like this:
CREATE TABLE `yourTable` (
`item_id` int(10) unsigned NOT NULL auto_increment,
`parent_id` int(10) unsigned default NULL,
`Name` varchar(50) NOT NULL,
PRIMARY KEY (`item_id`),
KEY `FK_parent_id` (`parent_id`),
CONSTRAINT `FK_parent_id` FOREIGN KEY (`parent_id`) REFERENCES `yourTable` (`item_id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Then, when you issue a DELETE statement, like:
DELETE FROM `yourTable` WHERE `item_id` = 1;
... it would delete each 'child' row, that has a parent_id of 1 as well. If any of those 'child' rows have children of their own, they'd be deleted too, etc. (that's what the ON DELETE CASCADE means).
Easier actually than thought:
DELETE FROM table WHERE id = # OR parent_id = #; //where # is the same in both places.
Example:
DELETE FROM table WHERE id = 1 OR parent_id = 1;

mysql foreign key error #1452

ALTER TABLE `groups` ADD FOREIGN KEY ( `company_id` ) REFERENCES `summaries`.`companies` (
`id`
) ON DELETE CASCADE ;
MySQL said:
#1452 - Cannot add or update a child row: a foreign key constraint fails (`summaries/#sql-164a_33c`, CONSTRAINT `#sql-164a_33c_ibfk_1` FOREIGN KEY (`company_id`) REFERENCES `companies` (`id`) ON DELETE CASCADE)
companies.id is primary auto increment int(11)
company_id is index int(11)
I don't understand the error message. Can anyone shed some light on this?
That means you have at least one row in the child table that references a non-existent row in the parent table.
If you are absolutely sure that you are okay with having a data integrity issue like that, you can add the foreign key by disabling foreign key checks before you run the ALTER TABLE command:
SET FOREIGN_KEY_CHECKS = 0;
I just had this problem, although in a somewhat more specific scenario.
In my case, I had added, to an existing table, a column that I needed to be both nullable and act as a foreign key (i.e., for non-null entries to be bound by a foreign key constraint).
The referenced column looked like this:
+-------------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+-------------+------+-----+---------+----------------+
| id | int(10) | NO | PRI | NULL | auto_increment |
+-------------+-------------+------+-----+---------+----------------+
and the referencing one like this:
+-------------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+-------------+------+-----+---------+----------------+
| bed_id | int(10) | YES | | NULL | |
+-------------+-------------+------+-----+---------+----------------+
Turned out that I had forgotten to specify DEFAULT NULL when adding the referencing column to the existing table and so it was automatically filled with zeros, which failed the foreign key constraint.
I changed them to NULL:
update devices set bed_id = NULL where bed_id = 0;
and then successfully added the foreign key constraint. Hope this helps someone
It looks like it tried to copy the groups table to a temp table in the summaries database.
MySQL tried to put the requested constraints on the temp table first. There may possibly be one or more rows in the groups table (hence the temp table also) whose company_id is no longer present in the summaries.companies table.
To verfiy : Try running a LEFT JOIN between groups and summaries.companies WHERE companies.id is NULL. If you get back any rows from that LEFT JOIN, you found the bad rows in the groups table.
Give it a Try !!!
Checks that "companies" table is not empty,if is empty and you have no data at moment.
set SET FOREIGN_KEY_CHECKS = 0;
like Ike said you before.

mysql foreign key concept

CREATE TABLE parent (id INT NOT NULL,
PRIMARY KEY (id)
) ENGINE=INNODB;
CREATE TABLE child (id INT, parent_id INT,
INDEX par_ind (parent_id),
FOREIGN KEY (parent_id) REFERENCES parent(id)
ON DELETE CASCADE
) ENGINE=INNODB;
I dont understand the meaning of putting ENGINE = INNODB here, and why do we use ON DELETE CASCADE?
engine=innodb will ensure you get foreign key support. The default MyISAM engine doesn't support foreign keys. On delete cascade will remove the child row if the referenced row in the parent table is removed.
MySQL is the DB engine. It can use multiple storage engines. MyISAM is the default storage engine for MySQL and it does not support foreign keys. InnoDB is another storage engine that does support foreign keys. You must specify ENGINE=InnoDB because MySQL will use MyISAM by default.
ON DELETE CASCADE will delete all rows in a table that have a foreign key that references a key that is deleted. I think it is dangerous and defeats a lot of the purpose of foreign key restriction, so I would avoid using it, but this is just my personal opinion.
Say you have:
+-------+-------+
| ordID | proID |
+-------+-------+
| 1 | 1 |
| 2 | 1 |
| 3 | 1 |
| 4 | 2 |
| 5 | 2 |
+-------+-------+
And on OrdersItems it has FOREIGN KEY (proID) REFERENCES Products (proID) ON DELETE CASCADE.
Then if someone runs
DELETE FROM Products WHERE proID = 2
Then rows with ordID 4 and 5 will also be deleted (it cascades).