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.
Related
mysql> delete from faculty where fid in ( select fid from class);
ERROR 1451 (23000): Cannot delete or update a parent row: a foreign
key constraint fails (ass1.class, CONSTRAINT class_ibfk_1
FOREIGN KEY (fid) REFERENCES faculty (fid))
This is throwing the mentioned error. What should I do?
It is dangerous to force this without knowing what the consequences are.
This error is happening because there is another table that has a foreign key association with something you're trying to delete. What do you want to happen to those rows in other tables that rely on the deleted data? Here are a few options:
If you want to delete those rows that rely on the data you're trying to delete, look into cascade deletion.
If you decide the data that relies on the data you need to delete should no longer have a foreign key constraint, you can drop the constraint.
If you don't want either of these things, consider not actually deleting your data, but instead using a boolean column to flag rows as "inactive". Then, you can filter on the flag when retrieving data if needed, while still maintaining old records that rely on that "obsolete" data.
You're trying to delete from parent table. Which is probably why you're getting an error.
Either set up the FK to cascade deletes:
YourForeignIDField INT NOT NULL REFERENCES ParentTable.ID ON UPDATE CASCADE ON DELETE CASCADE
Or set up the foreign ID to accept Nulls and cascade to null:
YourForeignIDField INT NULL REFERENCES ParentTable.ID ON UPDATE CASCADE ON DELETE SET NULL
Or delete all children first:
DELETE FROM ChildTable WHERE ForeignID = YourForgeignID;
DELETE FROM ParentTable WHERE ID = YourID;
I have a table:
CREATE TABLE person (
person_id INTEGER NOT NULL,
parent_person_id INTEGER REFERENCES person(person_id),
CONSTRAINT PK_person_id PRIMARY KEY (person_id)
);
Is there need to create index on parent_person_id column or it is created automatically?
You don't need to create the index on parent_person_id. Indexes are required on the referenced column, not the referencing one.
Also, be aware that there are some restrictions on creating same-table relationships. At the MySQL website, on the section on foreign-key relationships, it reads, "If ON UPDATE CASCADE or ON UPDATE SET NULL recurses to update the same table it has previously updated during the cascade, it acts like RESTRICT.
This means that you cannot use self-referential ON UPDATE CASCADE or ON UPDATE SET NULL operations. This is to prevent infinite loops resulting from cascaded updates."
This is a known limitation of MySQL and you should be aware to prevent apparently nonsensical errors.
foreign key indexed automatically in only InnoDB. In referencing table, there must be a column
where the foreign key columns are listed as the first columns in the same order.
Such an index is created on the referencing table automatically if it does not exist.
I want to start using table relations in a new project.
After some googling I got 2 tables set up as InnoDB:
The keys I want to link are
->users->userid (primary)
->sessions->userid (index)
The only thing that I don't understand in this process is what the different settings for "On update" and "On delete" do
The options here are:
-- (nothing?)
Cascade (???)
Set Null (sets everything to null?)
No action (well duh...)
Restrict (???)
I basically want the data in sessions to be deleted when a user is completely deleted
This since the sessions will only be deleted when the expiration is detected by my session manager...
So if anyone can tell me what these options do it would be much appreciated.
CASCADE will propagate the change when the parent changes. (If you delete a row, rows in constrained tables that reference that row will also be deleted, etc.)
SET NULL sets the column value to NULL when a parent row goes away.
RESTRICT causes the attempted DELETE of a parent row to fail.
EDIT: You didn't ask about them, but the SQL standard defines two other actions: SET DEFAULT and NO ACTION. In MySQL, NO ACTION is equivalent to RESTRICT. (In some DBMSs, NO ACTION is a deferred check, but in MySQL all checks are immediate.) The MySQL parser accepts SET DEFAULT, but both the InnoDB and NDB engines reject those statements, so SET DEFAULT can't actually be used for either an ON UPDATE or ON DELETE constraint.
Also, note that cascading foreign key actions do not activate triggers in MySQL.
The table containing the foreign key is called the referencing or child table, and the table containing the candidate key is called the referenced or parent table.
Set NULL : Sets the column value to NULL when you delete the parent table row.
CASCADE : CASCADE will propagate the change when the parent changes. If you delete a row, rows in constrained tables that reference that row will also be deleted, etc.
RESTRICT : RESTRICT causes you can not delete a given parent row if a child row exists that references the value for that parent row.
NO ACTION : NO ACTION and RESTRICT are very much alike. when an UPDATE or DELETE statement is executed on the referenced table, the DBMS verifies at the end of the statement execution that none of the referential relationships are violated. in short child row no concern if parent row delete or update.
The three main types of referential actions for foreign key constraints in SQL are Cascade, Set Null and Restrict.
CASCADE:
When a record in the parent table is deleted, any related records in the child table will also be deleted.
Example:
CREATE TABLE orders (
order_id INT NOT NULL,
customer_id INT NOT NULL,
PRIMARY KEY (order_id),
FOREIGN KEY (customer_id) REFERENCES customers(customer_id)
ON DELETE CASCADE
);
SET NULL:
When a record in the parent table is deleted, any related records in the child table will be set to NULL.
Example:
CREATE TABLE orders (
order_id INT NOT NULL,
customer_id INT,
PRIMARY KEY (order_id),
FOREIGN KEY (customer_id) REFERENCES customers(customer_id)
ON DELETE SET NULL
);
RESTRICT:
When a record in the parent table is deleted, an error will be thrown and the deletion will be prevented.
Example:
CREATE TABLE orders (
order_id INT NOT NULL,
customer_id INT NOT NULL,
PRIMARY KEY (order_id),
FOREIGN KEY (customer_id) REFERENCES customers(customer_id)
ON DELETE RESTRICT
);
I have a database that was originally in MyISAM and so had no foreign key constraints. As a result, there are quite a few orphaned rows where the record the foreign key refers to has since been deleted.
To fix this I decided to convert to InnoDB and add the foreign keys, with CASCADE for both updating and deleting. However, when I try to add the foreign key, I get errors like this (from Navicat 8 console):
1452 - Cannot add or update a child row: a foreign key constraint fails
(`database`.`#sql-1358_38d`, CONSTRAINT `#sql-1358_38d_ibfk_1` FOREIGN KEY
(`manufacturerID`) REFERENCES `manufacturer` (`ID`) ON DE)
I know why it's doing this - because of the orphaned rows. Is there a way though to have the creation of the constrain automatically clear out those rows? It will take ages to go through all of the tables and find orphaned rows.
This is one of the queries I'm running just in case it is suspect:
ALTER TABLE part_number ADD CONSTRAINT
FOREIGN KEY(manufacturerID)
REFERENCES manufacturer(ID)
ON DELETE CASCADE
ON UPDATE CASCADE;
write a query that finds the orphaned rows and then use that to delete. e.g
SELECT part_number.id FROM part_number LEFT JOIN manufacturer ON (manufacturer.ID = part_number.manufacturerID) where manufacturer.ID IS NULL
You need to get rid of all irrelevant records before you can add a constraint.
You can do it two ways.
1 Using not exists()
DELETE FROM part_number
WHERE NOT EXISTS (
select id from manufacturer
where part_number.manufacturerID = manufacturer.ID
)
2. Using a temporary table (a bit ugly, but i'll post it too)
-- create a temporary table
CREATE TEMPORARY TABLE `temp_ids`
(
`id` INTEGER
);
-- store all id's that need to be deleted
INSERT INTO `temp_ids`
SELECT part_number.id FROM part_number LEFT JOIN manufacturer ON (manufacturer.ID = part_number.manufacturerID)
WHERE ISNULL(`manufacturer.ID);
-- delete them
DELETE
FROM part_number
WHERE id IN (
SELECT `id` FROM `temp_ids`
);
-- drop the table
DROP TEMPORARY TABLE `temp_ids`;
See my related question: Handling database integrity
After all "dead" records are deleted, you will be able to add a constraint.
Hope this works for you :)
I'm deleting selected rows from both table in MYSQL, the two tables have foreign keys.
DELETE d,b
FROM A as b
INNER JOIN B as d on b.bid=d.bid WHERE b.name LIKE '%xxxx%';
MYSQL complains about foreign keys even though I'm trying to delete from both tables:
Error: Cannot delete or update a parent row: a foreign key constraint
fails (`yyy/d`, CONSTRAINT `fk_d_bid` FOREIGN KEY (`bid`) REFERENCES
`b` (`bid`) ON DELETE NO ACTION ON UPDATE NO ACTION)
what's the best solution here to delete from both table?
Change this constraint to use ON DELETE CASCADE -- which means that if a row is deleted, then any "child" rows will be automatically deleted as well.
Of course take good care of using CASCADE -- only use it when necessary. If you're overzealous with it, and accidentally do a well-placed DELETE, it might end up deleting half of your database. :)
See documentation on foreign key constraints.
I think I see what you're trying to do
If you can't change the table structure, then you could use 2 statements, the first with a sub-select
delete from B where bid IN (select bid from A where name like '%xxxx%');
delete from A where name like '%xxxx%';