MySql cascade delete from 2 tables - mysql

I have a MySql schema which uses class table inheritance, but I want the child tables to have cascade delete from the parent table, and a foreign table.
create table parent (
_key bigint unsigned not null,
name varchar(64) unique not null,
primary key(_key)
);
create table child_a (
_key bigint unsigned not null,
foreign_key_a bigint unsigned not null,
foreign key(_key) references parent(_key) on delete cascade,
foreign key(foreign_key_a) references a(_key) on delete cascade,
primary key(_key)
);
create table child_b (
_key bigint unsigned not null,
foreign_key_b bigint unsigned not null,
foreign key(_key) references parent(_key) on delete cascade,
foreign key(foreign_key_b) references b(_key) on delete cascade,
primary key(_key)
);
The issue is when a record is deleted from one of the foreign tables, it will delete the record from the child table, but not from the parent table. I would not like to use a stored procedure / multi-statement as a solution because the foreign tables have cascade deletes of their own, so I would need stored procedures for those as well.

ON DELETE CASCADE will delete the row in the table with the foreign key (child) when the row in the table it is referencing (parent) is deleted. Without ON DELETE CASCADE, the row with the foreign key (child) would be left pointing at a row (parent) which no longer exists and you would get an INTEGRITY CONSTRAINT VIOLATION.
There is no such problem the other way round, deleting the child without deleting the parent leaves no orphaned rows and no INTEGRITY CONSTRAINT VIOLATION as far as MySQL is concerned and no cascade is necessary.
If you wish to delete the child, parent and the other referenced row together you have a few options.
Multistatement/Procedure:
Delete the child first, then the parent and then the other record (no need for the ON DELETE CASCADEs)
Delete the child first, then the other record and then the parent (no need for the ON DELETE CASCADEs)
Delete the parent first, then the other record (only need ON DELETE CASCADE on the parent reference)
Delete the other record first then the parent (only need ON DELETE CASCADE on the other reference)
Trigger:
Place a trigger on AFTER DELETE on the child table that deletes the parent and the other record (in either order), then deleting the child will clear all three records (no need for the ON DELETE CASCADEs)
Change the relationship:
If you can change the relationship to the other table (a or b) so that it references the child and not the child referencing the other table (as you have currently), and keep the ON DELETE CASCADEs, deleting the parent row will clear the child and then the other record in turn.

Related

Why ON CASCADE DELETE is not working?

I want to delete rows from 2 tables in one query, so I do:
DELETE FROM form_questionnaire;
This is removing all rows from form_questionnaire but leaves rows in questionnaire. Why rows in questionnaire are not removed if there is ON DELETE CASCADE in form_questionnaire.questionnaire_id?
My tables
CREATE TABLE questionnaire(
id INTEGER AUTO_INCREMENT PRIMARY KEY NOT NULL,
content JSON,
creator VARCHAR(50) NOT NULL,
created TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE form_questionnaire(
form_id INTEGER,
questionnaire_id INTEGER,
FOREIGN KEY(form_id) REFERENCES form(id),
FOREIGN KEY(questionnaire_id) REFERENCES questionnaire(id) ON DELETE CASCADE
) ENGINE=INNODB;
database server
MySQL 5.7.21-20
You're thinking about cascades the wrong way around. What your current foreign key constraint is saying is "When you delete any row(s) in questionnaire, also delete any rows in this table (form_questionnaire) which reference those rows". That's the cascade.
I am not sure if I am understanding this incorrect OR it is your typing mistake. Foreign key will delete all rows from CHILD table (where FOREIGN KEY is defined) if related rows from master table are deleted.
That said, if you delete rows from questionnaire table, all related rows from form_questionnaire will be deleted automatically due to CASCADE DELETE.
What you have mentioned in question is opposite and does not happen so.

MySQL set ID of primary child with constraint

I have two MySQL tables where the primary relationship between the two is one-to-many. I also need a one-to-one relationship in the parent_table with the ID for the primary record from the child_table. You can kind of think of it as like a dad having lots of kids but having one kid that's his favorite ;P. Is it possible to setup a DB constraint such that a parent can have the ID of a child only if that child is a child of the parent?
parent_table (One)
id: Primary Key
primary_child_id: {ID from child table}
child_table (Many)
id: Primary Key
parent_table: {ID from parent table}
EDIT: The primary child is optional and child records will only be created for an already existing parent. The child_table can certainly be created after the parent_table.
Yes, it's possible, but it's tricky.
CREATE TABLE parent_table (
id INT PRIMARY KEY,
primary_child_id INT,
FOREIGN KEY (primary_child_id) REFERENCES child_table(id)
);
CREATE TABLE child_table (
id INT PRIMARY KEY,
parent_id INT NOT NULL,
FOREIGN KEY (parent_id) REFERENCES parent_table(id)
);
This is a circular reference, so you end up having a chicken-and-egg problem.
I resolve this by making the parent_table.primary_child_id a NULLABLE column, so you can create a parent row even before there are any child rows to reference. If you use NULL in the foreign key column on a given row, it's not a violation of the constraint.
The other tricky part is defining the tables in a circular reference relationship, when creating them as new tables. So you have to leave out one or the other constraint definition until both tables are defined, and then ALTER TABLE to add the missing constraint.
CREATE TABLE parent_table (
id INT PRIMARY KEY,
primary_child_id INT
);
CREATE TABLE child_table (
id INT PRIMARY KEY,
parent_id INT NOT NULL,
FOREIGN KEY (parent_id) REFERENCES parent_table(id)
);
ALTER TABLE parent_TABLE
ADD FOREIGN KEY (primary_child_id) REFERENCES child_table(id);
the parent [shouldn't be allowed to] have a favorite child that isn't his.
Okay, if you need the parent to reference only child records that reference itself:
ALTER TABLE child_table
ADD UNIQUE KEY (parent_id, id);
ALTER TABLE parent_TABLE
ADD FOREIGN KEY (id, primary_child_id) REFERENCES child_table(parent_id, id);
If you create the index in the child table before creating the foreign key, then the foreign key can use that index instead of creating a redundant index.
If I'm understanding correctly, a trigger which raises a SIGNAL should work:
DELIMITER $$
CREATE TRIGGER parent_child BEFORE INSERT ON parent_table
FOR EACH ROW
BEGIN
IF NOT EXISTS (SELECT 1 FROM child_table WHERE id = new.id)
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'Constraint failed';
ENF IF;
END;
$$
I'm not sure how you're choosing which table should get a record first when each depends on the other. So instead of this trigger you might prefer to write a stored procedure to create the "primary" relationship and validate it also with a SIGNAL.
Yes. You want the child's ID changes/deletions to cascade up to the parent's "favorite child" field, and the parent's ID changes/deletions to cascade down to all its children.
Your parent table should have id and favchild, where id is its primary key index. You would then make a foreign key for favchild that references the child table's primary key.
On the child table, you would make a parent field with a foreign key that references the parent table's id. Then you can have many children with one parent, and one child is the parent's favorite.
However, in order to do this, you need to disable foreign key constraints when you create the parent, because you will need to create at least one child at the same time.
Edit
If the parent must make sure favchild is actually a child: Since the parent row is added first, it would only be updated with favchild by some application logic. In which case you can do the check during that update. The only constraint from that point on would be if favchild were to change parents. So for that your parent table could have two extra columns instead of one: favchild_id and favchild_parent_id. Make those a combined index, with a combined foreign key that references the two columns of the child. ON UPDATE SET NULL. The only drawback here is if the child's ID were to change, it would also be nulled instead of cascaded to the parent.

Correct way to remove entry from a SQL table along with the relations

If we have TableA and TableB related by TableAB where TableAB has foreign keys for the first two table, then what's the go-to way of deleting an entry from TableA? Up to now if used a property such as IsActive with a bit to describe if the entry is still valid. However, that makes it a little problematic when there are "ghost entries" in the relation tables, such as TableAB.
How should I proceed?
One chaining table in question.
CREATE TABLE EntradaContadorCliente (
ClaveECC int AUTO_INCREMENT not null,
ClaveCliente int not null,
ClaveContador int not null,
ClaveEntrada int not null,
PRIMARY KEY (ClaveECC),
FOREIGN KEY (ClaveCliente) REFERENCES Cliente(ClaveCliente),
FOREIGN KEY (ClaveContador) REFERENCES Contador(ClaveContador),
FOREIGN KEY (ClaveEntrada) REFERENCES EntradaBitacora(ClaveEntrada)
);
Since TableA and TableB related by TableAB; which means TableAB is a chaining table. One way is to use ON DELETE CASCADE for cascading the delete operation on primary table.
Alternative is to, manually delete the entries from your chaining table once the entry has been deleted from primary table.
You can use a ALTER statement to re-create the FK constraint like
ALTER TABLE `TableAB` DROP FOREIGN KEY FK_KEY_Test;
ALTER TABLE `TableAB` ADD CONSTRAINT FK_KEY_Test FOREIGN KEY ('some_column')
REFERENCES `TableA` ('Test_column1') ON UPDATE CASCADE ON DELETE CASCADE;
From MySQL Documentation:
CASCADE: Delete or update the row from the parent table, and
automatically delete or update the matching rows in the child table.
Both ON DELETE CASCADE and ON UPDATE CASCADE are supported.
first you disable all foreign key with:-
alter table table_name
nocheck constraint fk_constraint
then you delete data in parent table.

Update records with foreign keys when a record is deleted [duplicate]

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

Setting up table relations what do "Cascade", "Set Null" and "Restrict" do?

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