SQL Create Trigger Before Delete vs. Foreign Key On Delete - mysql

I have one table referencing another. As I see - there are two ways to delete cascading:
What is the difference between CREATE TRIGGER BEFORE DELETE and FOREIGN KEY ON DELETE? Are there any differences in performance?
I came up with this advantage of FOREIGN KEY:
The cascading delete is more obvious because it's attached in the table definition.
Full question:
I have the two tables:
project(id, ...) <- works_on(id, project_id, ...)
What are the differences in
CREATE TABLE works_on (
...
FOREIGN KEY (project_id) REFERENCES project ON DELETE CASCADE
...
);
and
CREATE TRIGGER trigger_delete_cascading
BEFORE DELETE ON project
DELETE works_on
WHERE project_id = id;

A FOREIGN KEY will restrict values that can be stored in the project_id column of the works_on table. You will not be able to set a value that does not exist in the project table.
A TRIGGER does not restrict the range of values that can be stored.

If wrote trigger BEFORE delete,will DELETE record from CHILD TABLE and due to some Server error or Other constraint if record is unable to delete from MAIN TABLE(PARENT) then it makes redundant data.
So whenever you required delete plus more action like maintaining LOG table then only you have to go with Trigger.Otherwise ON DELETE CASCADE is great to work.
Hope this will helps you.

Related

how can I delete my child row in sql if it's failing?

When I execute the next SQL code:
delete from product where idproduct = 2;
I get the next error:
Error Code: 1451. Cannot delete or update a parent row: a foreign key constraint fails (`store`.`sale_detail`, CONSTRAINT `fk_sale_detail_product1` FOREIGN KEY (`idproduct`) REFERENCES `product` (`idproduct`) ON DELETE NO ACTION ON UPDATE NO ACTION)
when I try to delete the child of my table dont want, but however I just want to delete product rows without delete brands..
Image of brand table: Brand table
Image of product table: Product table
You can't since that violates Referencial Integrity Constraint rule. You should chose cascading option saying ON DELETE CASCADE.
You need to delete the child row first and then delete the parent row.
You can temporarily disable FK check saying SET FOREIGN_KEY_CHECKS=0; and enable them once done with deletion.
Drop all FK constraint, perform delete and then recreate FK constraint again.
Best option: Go for a soft delete by having a Status column in your table and just update that column to Deleted instead.
You have a foreign key constraint on your store.sale_detail table in the idproduct column. So if you are trying to delete a product you need to be sure that product is not referenced on the sale_detail table.
Another solution is to modify your foreign key so when you delete a row on the product table the referenced row on the sale_detail gets NULL on the corresponding column. Actually you have:
ON DELETE NO ACTION
But you can have:
ON DELETE SET NULL
Also, you can force to delete all references on the sale_detail table:
ON DELETE CASCADE
Hope it helps.

mysql foreign key "permissions" on delete

I'm working on a little support (ticket) system. My tables are tickets and ticket_replies.
Design of tickets table is
id|user_id|title|...
Design of ticket_replies looks like:
id|ticket_id|...
The foreign key I added looks like this:
ALTER TABLE `ticket_replies` ADDFOREIGN KEY (`ticket_id`)
REFERENCES `sampleauth`.`tickets`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
Now when I delete a "ticket" in the "ticket" table it gets deleted in "ticket_replies" too. The other way this doesn't work, all in all I would like this to work the other way too, so my database has all the time consistency. How to do so?
Add this trigger will delete its primary key when you try to delete foreign key
CREATE TRIGGER `ticket_replies_BEFORE_DELETE` BEFORE DELETE ON `ticket_replies` FOR EACH ROW
BEGIN
DELETE FROM tickets WHERE id = OLD.ticket_id;
END

SQL: Cannot delete or update parent row: a foreign key constraint fails

Whenever I try to delete a survey from table "survey" like this:
DELETE FROM surveys WHERE survey_id = 77
It prompts me an error stated below:
#1451 - Cannot delete or update a parent row: a foreign key constraint fails ('user_surveys_archive', CONSTRAINT
'user_surveys_archive_ibfk_6' FOREIGN KEY ('user_access_level_id')
REFERENCES 'user_surveys' ('user_access_level_id') ON DELETE NO ACTION
)
First thing: I do not have any such table with this name "user_surveys_archive_ibfk_6"
2nd thing: There is no record of this survey in other tables.
Any idea on how can I delete this record of fix this issue?
Edit
This is the line I found when I export the table Constraints for table surveys
ALTER TABLE `surveys`
ADD CONSTRAINT `surveys_ibfk_1` FOREIGN KEY (`survey_type_id`) REFERENCES `survey_types` (`survey_type_id`) ON DELETE CASCADE ON UPDATE NO ACTION;`
You will need to first remove or update some rows in table user_surveys_archive.
Those rows are related to rows in the user_surveys table.
Likely, there's a foreign key constraint defined on table user_surveys that references rows in surveys you are attempting to delete.
(You'd need to check the foreign key definition, quickest way to get that is a
SHOW CREATE TABLE user_surveys
And look for REFERENCES surveys. (Likely, its a column named survey_id, but we're just guessing without looking at the definitions of the foreign key constraints.)
To find the rows in user_surveys_archive that are preventing the DELETE from happening...
SELECT a.*
FROM user_surveys_archvive a
JOIN user_surveys u
ON u.user_access_level_id = a.user_access_level_id
JOIN surveys s
ON s.survey_id = u.survey_id -- change this to whatever the FK is
WHERE s.survey_id = 77
It's likely that the foreign key constraint from user_surveys to surveys is defined with ON DELETE CASCADE. The attempt to delete rows from surveys identifies rows in user_surveys that should automatically be removed.
The attempt to automatically remove the rows from user_surveys is what's violating the foreign key constraint defined in user_surveys_archive. And that foreign key is not defined with ON DELETE CASCADE.
(The other possibility is that there's a trigger defined that's doing some DML operations, but that would be odd.)
Once you identify the rows, you need to decide what changes to make to allow you to remove rows from surveys.
You can either DELETE the rows, or UPDATE them.
To delete the rows from user_surveys_archive, modify the query above and replace SELECT with DELETE. If the user_access_level_id column in user_surveys_archive allows for NULL values, you can do an update.
Replace SELECT a.* FROM with UPDATE, and add SET a.user_access_level_id = NULL on a line above the WHERE clause...
UPDATE user_surveys_archvive a
JOIN user_surveys u
ON u.user_access_level_id = a.user_access_level_id
JOIN surveys s
ON s.survey_id = u.survey_id -- change this to whatever the FK is
SET a.user_access_level_id = NULL
WHERE s.survey_id = 77
(It seems strange to me that name of the foreign key column is user_access_level_id. But its just a column name, it could be named anything... seems odd to me because of the conventions and patterns that we follow in naming foreign key columns.)
You should allow the foreign key to be NULL and then choose ON DELETE SET NULL.
Personally I would recommend using both "ON UPDATE CASCADE" as well as "ON DELETE SET NULL" to avoid unnecessary complications, however your setup may dictate a different approach.
Hope this helps.
The survey_id of 77 must be referenced in a table possibly named user_surveys_archive. The error is saying the name of the foreign key restraint which is the user_surveys_archive_ibfk_6. If you need to delete survey_id = 77 you will have to delete any child records or other records that reference it as a foreign key.
Edit After posting my answer I saw the comments above. atif the foreign key in the user_surveys_archive table may be named differently but still equal the value of 77 that you are trying to delete, and/or be referencing the survey_id. If that is not the case then there are some other problems within the database. You could try and look at the code for the FK to see how it was made and what fields it is referencing, or run a query to see if there are any records in the user_surveys_archive where the user_access_level_id is = 77.
Edit 2 spencer7593's answer lays out how to run some of the queries mentioned in my answer.

MySQL InnoDB - create CASCADE foreign key constraint when data already exists that violates it?

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 :)

mysql delete and foreign key constraint

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%';