mysql foreign key update constraint in a transaction? - mysql

I can not find official mysql explanation about this, so I wanna throw it here.
If I have foreign key constrains between two tables in MySQL, say tableA is the parent table, tableB is the child table. And, on parent tableA, I will use "ON UPDATE CASCADE ON DELETE CASCADE" to make sure actions of update/delete can be applied to child tableB by MySQL automatically.
Now, my question is: if the update to child table and parent table is in a transaction or not?
Or by using the following statements, any differences?
Method 1:
UPDATE tableA SET col1="A" and col2="B";
Method 2:
Begin;
UPDATE tableA SET col1="A" and col2="B";
Commit;
Now, I met the problems in method1: when tableA is updated, tableB might take very long to update its corresponding columns(not in a transaction for sure).
Anyone met similar problems before?

Assuming all of your tables are using InnoDB, then almost all actions you do while in a transaction are covered by that transaction and can be rolled back. Somethings, like DROP TABLE do an implicit commit. But for select/update/insert/delete, it's all covered.
That includes any inserts/updates/deletes that are triggered by a foreign key cascade relationship.

say tableA is the parent table, tableB is the child table. And, on
parent tableA, I will use "ON UPDATE CASCADE ON DELETE CASCADE" to
make sure actions of update/delete can be applied to child tableB by
MySQL automatically.
If tableA has ON UPDATE CASCADE ON DELETE CASCADE, then tableA is the "child", not the "parent". (SQL doesn't use the terms "parent" and "child"; tableA is the referencing table, and tableB is the referenced table.) Changes to the referenced column in tableB will automatically be applied to matching values in tableA.
create table tableB (
column_a char(2) primary key
);
create table tableA (
column_a char(2) not null
references tableB (column_a)
on update cascade
on delete cascade,
column_b char(2) not null,
primary key (column_a, column_b)
);
insert into tableB values ('aa');
insert into tableA values ('aa', 'bb');
update tableB
set column_a = 'cc'
where column_a = 'aa';
select *
from tableA;
column_a column_b
--
cc bb
An update that cascades because of foreign key references is a single transaction. SQL has to work that way. If the update were two transactions--one for the referenced table and one for the referencing table--and the update to the referencing table failed, it would leave the database in an inconsistent state. (For example, in the update above, because 'aa' would have changed to 'cc' in tableB, but not in tableA. The dbms can't let that happen.)

Related

Using ON DELETE CASCADE without updating foreign key

I have to delete data in multiple table with foreign key relation. I can easily do it with ON DELETE CASCADE rule in my foreign key definition but I do not want to do that. I just want to create a query that can perform an ON DELETE CASCADE capability without updating my FK but I do not have ant idea how.
I tried creating multiple delete statement, one for each table but that seemed to be too hassle.
What is the easiest way to delete data from a multiple table with FK relationship?
While on delete cascade is the prefered way to do this, you can also do this with a single delete query, since it supports deletion from multiple tables. If you can properly join your tables (which you trivially should be able to do via their foreign key relations), you can delete from them at once:
You can specify multiple tables in a DELETE statement to delete rows from one or more tables depending on the condition in the WHERE clause. [...], only matching rows from the tables listed before the FROM clause are deleted.
So you can use for example:
CREATE TABLE parent (
id INT PRIMARY KEY
);
CREATE TABLE child (
id INT PRIMARY KEY,
parent_id INT,
FOREIGN KEY (parent_id) REFERENCES parent (id)
);
INSERT INTO parent(id) VALUES (1), (2), (3);
INSERT INTO child(id, parent_id) VALUES (1,1), (2,1), (3,2), (4,2), (5,3), (6,3);
SET FOREIGN_KEY_CHECKS=0;
DELETE child, parent
FROM child
JOIN parent ON child.parent_id = parent.id
WHERE parent.id = 1;
SET FOREIGN_KEY_CHECKS=1;
You have very little control over the deletion order, and in almost every case, MySQL will prefer an execution order that would violate the foreign key constraints (since that is probably the only viable way to join your tables), so for this to work you will need to disable FOREIGN_KEY_CHECKS temporarily; see also the remark in the manual:
If you use a multiple-table DELETE statement involving InnoDB tables for which there are foreign key constraints, the MySQL optimizer might process tables in an order that differs from that of their parent/child relationship. In this case, the statement fails and rolls back. Instead, you should delete from a single table and rely on the ON DELETE capabilities that InnoDB provides to cause the other tables to be modified accordingly.

Mysql: Multiple Insert with Select, foreign key fails

I try to "duplicate" several rows in my table A. This table (A) has only two fields wich are foreign keys. One referencing to table B and the other one to table C.
Now I'd like to take several rows from A and re-insert (duplicate) them into A. Doing that I am changing one of the foreign keys (FK1).
INSERT INTO `A` (`FK1`, `FK2`) VALUES (".$newFK.", 1);
This code works without any problem. But I need to duplicate more than just one row. Of course, I can do an SELECT-Statement and use the fetch_array to insert every row one by one but I'd like to solve it more elegant. Like this:
INSERT INTO A (`FK1`, `FK2`) SELECT ".$newFK.", `FK2` FROM `A` WHERE `FK1` = '".$tobeduplicatedFK."';
As well I have tried
INSERT INTO `A` SET `FK1` = ".$newFK.", `FK2` = (SELECT `FK2` FROM `A` WHERE `FK1` = '".$tobeduplicatedFK."');
Unfortunately neither of those work. But I do receive the "Cannot add or update a child row: a foreign key constraint fails" - Error related with FK1. Since the inelegant version is working the new FK1 ($newFK) exists. I have checked the old FK1 ($tobeduplicatedFK) as well and it exists, too.
I thought maybe something messes up because the select statement is on the same table and using the FK that has to be changed in WHERE-Clause. I have tried to perform the SELECT-Statement selecting from A as Asource but it is failing as well.
Any idea why it is failing?
Try a subquery:
"INSERT INTO A
(
FK1,
FK2
)
SELECT
FK1,
FK2
FROM
(SELECT
{$newFK} AS FK1,
FK2
FROM
A
WHERE
FK1 = {$tobeduplicatedFK}) x0;"

Implement Foreign Key in mysql table

Im trying to restore some old database tables, that when i build them i did not user foreign keys. I have the field that corresponds to the Foreign Key, but i've not set it up in the relations table to which table it connected.
Right know i have a problem because if i try to add that relation, it cannot, because there are some rows deleted in the other table.
Is there any mysql command for checking this type NULL relations for me to delete the rows that i dont need.. and in the end.. add the relation.
TableA
id,
name
TableB
id,
tableA_id,
points
I've deleted some TableA rows.. now i cannot had that relation.
Any mysql command to help, or need to check manually?
Thanks
Assuming that you have PRIMARY KEY constraint at least on TableA.id you can try
-- Delete all orphaned records from TableB
DELETE b
FROM tableb b LEFT JOIN tablea a
ON b.a_id = a.id
WHERE a.id IS NULL;
-- Create a FK constraint
ALTER TABLE TableB
ADD CONSTRAINT fk_a_id FOREIGN KEY (a_id) REFERENCES tablea(id);
Here is SQLFiddle demo

how to update a primary key if it is also the foreign key to another table?

I have a table, tableA, which has a column myID. myID is a primary key in tableA and foreign key to tableB.
when i tried to update a particular record's myID in tableA:
update tableA
set myID = 123456
where myID= 999999
i got this error:
The UPDATE statement conflicted with the FOREIGN KEY constraint
"tableA_FK00". The conflict occurred in database "mydatabase" , table
"tableA" , column 'myID'.
i had set myID's Update Rule to 'Cascade' and Enforce Foreign Key Constraint to 'No' but i still cannot update. how should i proceed?
If there's a record in tableB that references tableA with PK 123456 and tableB is the table with the "tableA_FK00" constraint then you are violating the constraint. If you must change the PK of a row in tableA (and I'm not sure why you're doing that, PK's should never change!!!) you have the burden of making sure no other records reference it with FK constraints.
So if you insist on changing the PK in tableA:
Find which table has the constraint "tableA_FK00" (ensure it's only tableB see post here).
Temporarily remove the constraint in tableB
Update tableA
Update all rows in TableB that need their FK changed
Reapply FK constraint on tableB
Another option:
Insert all ids of rows from tableB with FK 123456 into a temp table (this table just has the keys of PK's from tableB)
Set tableB FK field to allows nulls
Set all fields in tableB FK = null by joining with the temp table on tableB PK
Change the row in tableA
Set all the rows in tableB to 999999 by joining with the temp table.
Try these steps:
Disable FK constraints temporarily (ALTER TABLE tableA WITH NOCHECK
CONSTRAINT ALL).
Update your Primary Keys
Update your Foreign Keys to match the Primary Keys change
Enable back enforcing FK constraints

MySQL Multi-Delete. Is it possible to multi-delete referenced rows?

If I have a parent table and a child table, is it possible to multi-delete the rows in them without having a "ON DELETE CASCADE" constraint?
In this example:
create table a(id int primary key);
create table b(id int primary key, a_id int,
constraint fkb foreign key (a_id) references a(id));
Is it not possible to do something like this in order to delete rows in tables a and b? :-(
delete a, b
from b
inner join a on a.id = b.a_id
where a.id = ?;
Error Code: 1451. Cannot delete or update a parent row: a foreign key constraint fails
(`erasmusu6`.`b`, CONSTRAINT `fkb` FOREIGN KEY (`a_id`) REFERENCES `a` (`id`))
I would like to multidelete rows but not to set a "ON DELETE CASCADE" constraint. Also I need to filter the DELETE command with a WHERE clause. Is this possible or should I have to make as many DELETEs as tables in the multidelete?
I solve the problem with optimizer hints, by specifying the exact join order in the DELETE command:
delete a, b
from b
STRAIGHT_JOIN a on a.id = b.a_id
where a.id = ?;
MySQL will DELETE b rows first thanks to the optimizer hint STRAIGHT_JOIN.
This is the note from mysql documentation page (http://dev.mysql.com/doc/refman/5.0/en/delete.html):
"If you use a multiple-table DELETE statement involving InnoDB tables for which there are foreign key constraints, the MySQL optimizer might process tables in an order that differs from that of their parent/child relationship. In this case, the statement fails and rolls back. Instead, you should delete from a single table and rely on the ON DELETE capabilities that InnoDB provides to cause the other tables to be modified accordingly."
So, this implies that you are forced not to use multi delete option!
Hope that helps..