Delete records with recursive foreign key constraints - mysql

What is the best approach to delete records from a table which has a foreign key to another table and the other table has a foreign key to it?
For instance, I have the following tables. accounts has one or more networks and accounts must have a single default network.
CREATE TABLE IF NOT EXISTS accounts (
id INT NOT NULL,
networksId INT NOT NULL,
PRIMARY KEY (id),
INDEX fk_accounts_networks1_idx (networksId ASC),
CONSTRAINT fk_accounts_networks1
FOREIGN KEY (networksId)
REFERENCES networks (id)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
CREATE TABLE IF NOT EXISTS networks (
id INT NOT NULL AUTO_INCREMENT,
accountsId INT NOT NULL,
PRIMARY KEY (id),
INDEX fk_sites_accounts1_idx (accountsId ASC),
CONSTRAINT fk_sites_accounts1
FOREIGN KEY (accountsId)
REFERENCES accounts (id)
ON DELETE CASCADE
ON UPDATE NO ACTION)
ENGINE = InnoDB;
Even though I have a CASCADE DELETE on networks FK to accounts, I tried to explicitly delete networks in hopes of getting around the foreign key constraint, however, was not successful.
DELETE a, n FROM accounts a INNER JOIN networks n ON n.accountsId=a.id WHERE a.id=123;
Is my only solution something like the following?
SET FOREIGN_KEY_CHECKS=0;
DELETE FROM networks WHERE accountsId=123;
SET FOREIGN_KEY_CHECKS=1;
DELETE FROM accounts WHERE id=123;

You have a constraint interdependency between both tables. This is not a good design, because it tends to make DDL and DML operations more complicated than normally necessary.
Apart from temporarily disabling a foreign key, the only possible solution to perform a successful DELETE is to make one of the referencing fields nullable so you can break the relation by setting it to NULL before deleting. The ON DELETE CASCADE will take care of dropping the related record in the other table.
Make one the referencing fields nullable :
ALTER TABLE networks MODIFY accountsId INT NULL;
Delete :
UPDATE network SET accountsId = NULL WHERE id = ?;
DELETE FROM network WHERE id = ?;
-- the corresponding record in table accounts gets automatically deleted.

Related

Issiue with ON DELETE CASCADE?

I have a question about ON DELETE CASCADE, i have made thise tables as an example.
CREATE TABLE shop_articles(
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255),
description TEXT
);
CREATE TABLE shop_articles_images(
id INT AUTO_INCREMENT PRIMARY KEY,
article_id INT,
description VARCHAR(255),
image VARCHAR(255),
FOREIGN KEY (article_id) REFERENCES shop_articles (id)
);
In order to delete all the data affiliated with the main table, i am using this ALTER TABLE command after adding the tables.
ALTER TABLE shop_articles_images
ADD CONSTRAINT shop_articles_images_ibf5
FOREIGN KEY (article_id) REFERENCES shop_articles (id)
ON DELETE CASCADE;
It seams alltough this have been added i cant delete rows from the main table, i dont want to manually delete the other affiliated tables, but delete it when delete from the main table.
Any one have experience with this, or can see what i do wrong here? does this altertable reset when the mysql server is restarted?
I think you have some confusion about how ON DELETE CASCADE works. If your engine is MyISAM, which does not enforce foreign keys, then no cascading deletes will happen. If your engine is InnoDB, then if you delete a record from the main table shop_articles then any records in shop_articles_images which are linked to the main table via a key relationship will also be deleted.

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.

MySQL table with more indexes than columns

I am working with an InnoDB MySQL database from MySQL workbench and am stuck on the indexes for one table.
I have a table
╔═══════════════╗
║ poll_votes ║
╟───────────────╢
║pk poll_id fk║ //references polls.id
║pk voter_id fk║ //references users.id
║ option_id fk║ //references poll_options.id
╚═══════════════╝
Since the primary key is a composite key, MySQL automatically generates a multi-column index for poll_id and voter_id. Since each foreign key must have an associated index, MySQL further generates 3 additional indexes corresponding to the 3 columns.
Now I have 4 indexes on a 3-column table, and MySQL Workbench won't let me delete any of them, even though one of them is redundant. Furthermore, I'll never need the option_id index, so that's just wasting space.
Is having more indexes than columns going to hurt me here, or should I not worry about it? Is there a better way to design this table?
EDIT: The SQL (I edited some of the field names so there's a possibility there's a typo in here):
CREATE TABLE `poll_votes` (
`poll_id` int(11) NOT NULL,
`voter_id` int(11) NOT NULL,
`poll_option_id` int(11) NOT NULL,
PRIMARY KEY (`poll_id`,`voter_id`),
KEY `fk_poll_votes_polls1_idx` (`poll_id`),
KEY `fk_poll_votes_poll_votes1_idx` (`poll_option_id`),
KEY `fk_poll_votes_users1_idx` (`voter_id`),
CONSTRAINT `fk_poll_votes_polls1` FOREIGN KEY (`poll_id`) REFERENCES `polls` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION,
CONSTRAINT `fk_poll_votes_poll_options1` FOREIGN KEY (`poll_option_id`) REFERENCES `poll_options` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION,
CONSTRAINT `fk_poll_votes_users1` FOREIGN KEY (`voter_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION
)
SET foreign_key_checks = OFF;
CREATE...
SET foreign_key_checks = ON;
(No, I don't understand why that flag is controlling the issue you encountered.)

Foreign Key CASCADE DELETE for table with multiple parents?

I am very new to foreign keys and CASCADE operations, and am wondering about the following scenario:
Let's say I have two completely different parent tables (HUMAN and ALIEN) with completely different data. Now, what I want to do is create a child table named SPACESHIP, as both humans and aliens can own spaceships, with an FK that would point to either a row in HUMAN or a row in ALIEN, in the hopes that if I delete either a human row or an alien row, it would Cascade Delete the corresponding spaceship rows owned by the respective parent. Is there a good way to do this with FK's and CASCADE DELETE? Or should I just have a column in HUMAN and ALIEN called spaceship_id and handle the delete of spaceships manually / via trigger? Some other course of action?
Help!
This can be solved by adding a supertype table (lets call it Being) that has as subtypes the two Human and Alien tables. Then the FOREIGN KEY constraint would reference this superype table.
The supertype:
CREATE TABLE Being
( BeingId INT AUTO_INCREMENT
, ... other stuff about beings
, PRIMARY KEY (BeingId)
) ENGINE = InnoDB ;
the subtypes:
CREATE TABLE Human
( BeingId INT --- not AUTO_INCREMENT
, ... other stuff about humans
, PRIMARY KEY (BeingId)
, CONSTRAINT Being_Human_fk
FOREIGN KEY (BeingId)
REFERENCES Being(BeingId)
ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE = InnoDB ;
CREATE TABLE Alien
( BeingId INT --- not AUTO_INCREMENT
, ... other stuff about aliens
, PRIMARY KEY (BeingId)
, CONSTRAINT Being_Alien_fk
FOREIGN KEY (BeingId)
REFERENCES Being(BeingId)
ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE = InnoDB ;
and the Spaceship table:
CREATE TABLE Spaceship
( SpaceshipId
, SpaceshipName
, OwnerId
, ... other stuff about spaceships
, PRIMARY KEY (SpaceshipId)
, CONSTRAINT Being_Spaceship_fk
FOREIGN KEY (OwnerId)
REFERENCES Being(BeingId)
ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE = InnoDB ;
If you use InnoDB storage engine, then you can use foreign keys, because currently only InnoDB supports them. Otherwise you can use triggers or delete parent and child records using one query, e.g.:
DELETE HUMAN, SPACESHIP
FROM HUMAN
JOIN SPACESHIP
ON HUMAN.id = SPACESHIP.id
WHERE HUMAN.id = 1;

delete primary key also deletes foreign key

I have two table, with a PK of ID. If say I delete the entry for ID = 1, I want it to automatically delete the FK of ID in the other table. In other words I want so that it should also delete all entries with ID = 1 in the other table. How can I do this? I have linked the PK-FK relationship, but when I delete the entry with ID 1 in the PK table it doesn't delete the FK.
Make sure you're using the InnoDB engine for both tables, and add a foreign-key constraint specifying on delete cascade. Your table creation SQL should look something like this:
create table child_table (
parent_id int references parent_table(id) on delete cascade
) engine 'innodb';
where child_table and parent_table are the names of your child and parent tables.
You have to define your Foreign Key constraints as ON DELETE CASCADE.
Note: You need to use InnoDB storage engine, he default MyISAM storage engine not support foreign keys relation.
CREATE TABLE `table2` (
`id` int(11) NOT NULL auto_increment,
`name` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `ids` (`ids`)
CONSTRAINT `foreign` FOREIGN KEY (`ids`)
REFERENCES `table2` (`ids`) ON DELETE CASCADE ON UPDATE CASCADE
)