How to delete rows from table sql - mysql

I want to delete specific rows from 8 tables.
My problem is that the rows are connected with foreign key.
How can I delete all the data that connected to the specific rows that I want to delete?
My tables include definition tables (like id, name ,max value, min value...),
data tables (like id, user_id, definition_id,....) and history tables (save every change in data table).
I thought to use delete on cascade command but I could not find a way to use it.

DELETE CASCADE is an attribute of the foreign key constraint. Unfortunately it's not something you can use as an option with a DELETE statement (which would be really cool actually)
If your foreign keys have not been declared as cascading you need to "work your way up".
Unfortunately you did not show us your real table structure so let's assume something like this:
main_table (main_id)
child_one (id, main_id)
child_two (id, id_one)
child_three (id, id_two)
(I know you said 8 tables, but for the sake of the demonstration I shortened it a bit, but that doesn't change the underlying "strategy")
Assuming you want to delete the row with main_id = 42 from `main_table:
You first need to delete the rows from child_three using something like this:
delete from child_three
where id_two in (select id
from child_two
where id_one in (select id
from child_one
where main_id = 42);
Then delete the rows from child_two:
delete from child_two
where id_one in (select id
from child_one
where main_id = 42);
Then child_one:
delete from child_one
where main_id = 42;
And finally the main table:
delete from main_table
where id = 42;
Some SQL clients can actually generate those statements for you. I don't know if SQL Developer can though.

I assume that you use InnoDB Engine, since you are talking about foreign keys,
Easier will be to define properly the table so that a deletion will act as a cascade deletion.
CONSTRAINT `myForeignKey` FOREIGN KEY (`typeId`)
REFERENCES `types` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
Here is alink with a proper create table statement:
How do I use on delete cascade in mysql?

Related

Easily alter table data to add foreign keys without restraints

I'm trying to add foreign keys to a testing database seeded with a bunch of dummy data. I could go outside MySQL, export a list of missing IDs, and generate a bunch of insert statements in Python but I'm wondering if there is a way to handle this in MySQL
ALTER TABLE `kalos`.`award`
CHANGE COLUMN `awardee_user_id` `awardee_user_id` INT(11) NULL ;
ALTER TABLE `kalos`.`award`
ADD CONSTRAINT `fk_award_3`
FOREIGN KEY (`awardee_user_id`)
REFERENCES `kalos`.`user` (`user_id`)
ON DELETE RESTRICT
ON UPDATE CASCADE;
I've tried messing with the ON DELETE and ON UPDATE properties but it definitely won't let me apply it because there are user ID's in the award table that are not present in the user table (only about 200 out of 3000). Like I said it would be fairly simple to do this in Python but I've run into this issue a few times and am really curious to see if MySQL can handle something like this on it's own.
I figured this out and it was extremely simple.
DELETE FROM t1
WHERE
t1.id NOT IN (SELECT
id
FROM
(SELECT
tmp.id AS id
FROM
t1
INNER JOIN t2 ON t1.id = t2.id) as tmp)
This will delete any row from t1 that does not have a corresponding record in t2

Copying from one table to other, how to enforce foreign key check on the whole data set but not on separate rows?

I'm using MySQL. Let's assume I have a table hierarchy with two columns: id, parent_id.
The parent_id refers to id of other row of the same table, so I have the foreign key there.
The hierarchy table contains some data, but they are not relevant now.
I also have a second table called new_hierarchy_entries that has the same columns, but there are no foreign key restrictions set.
new_hierarchy_entries contains:
id parent_id
2 1
1 null
Now I want to copy all the rows from new_hierarchy_entries into hierarchy. When I run naively:
INSERT INTO hierarchy SELECT * FROM new_hierarchy_entries
I get error: Cannot add or update a child row: a foreign key constraint fails (my_db.hierarchy, CONSTRAINT hierarchy_ibfk_2 FOREIGN KEY (parent_id) REFERENCES hierarchy (id))
Of course, if the rows are inserted one by one, the first row (id=2, parent=1) cannot be inserted, because there is no row with id=1 in table hierarchy.
On the other hand, if all rows were added at once, then the constraints would be satisfied. So how can I copy the rows in such a way that I'm sure that constraints are satisfied after the copying, but they may not be satisfied while copying?
Sorting rows of new_hierarchy_entries by id will not help. I cannot assume that parent_id < id in the same row.
Sorting rows of new_hierarchy_entries by the hierarchy (using tree terminology, give me leaves first, then their parents etc.) would help, but I'm not sure how to do that in MySQL query.
I played with the idea of temporarily turning the FOREIGN_KEY_CHECKS off. But then I could insert inconsistent data and I wouldn't find out. Turning FOREIGN_KEY_CHECKS on doesn't make the database check consistency of all the data. It would take too much resources anyway.
This is tricky. I don't know any way to make MySQL re-check foreign key references after enabling FOREIGN_KEY_CHECKS.
You could check yourself for orphan rows, and if there are any, roll back.
BEGIN;
SET SESSION FOREIGN_KEY_CHECKS=0;
INSERT INTO hierarchy SELECT * FROM new_hierarchy_entries;
SET SESSION FOREIGN_KEY_CHECKS=1;
SELECT COUNT(*) FROM hierarchy AS c
LEFT OUTER JOIN hierarchy AS p ON p.id=c.parent_id
WHERE p.id IS NULL;
-- if count == 0 then...
COMMIT;
-- otherwise ROLLBACK and investigate the bad data
One other possibility is to use INSERT with the IGNORE option, which will skip failed rows. Then repeat the same statement in a loop, as long as you see "rows affected" more than 0.
INSERT IGNORE INTO hierarchy SELECT * FROM new_hierarchy_entries;
INSERT IGNORE INTO hierarchy SELECT * FROM new_hierarchy_entries;
INSERT IGNORE INTO hierarchy SELECT * FROM new_hierarchy_entries;
...

Delete all descendants of an entry (MySQL)

I have a table with, let's say, the following columns:
Name , Parent Name, ID
Let's also say that there are three entries where Parent Name is Null (meaning they are the top-most parent) - F_one, G_one, and H_one.
If I want to delete all the descendants of one of those parents (G_one, why not?) meaning all the children of G_one, all the children of those children, and the children of those, and so on all the way until the terminal level where, that row's Name does not exist as a Parent Name for any other entry.
Is that possible to be done easily, maybe with a single query?
Bonus, is there a way to select all of the G_one lineage so I can manipulate it to my whim and will?
Can assume:
-No Children are shared among parents
Cannot assume:
-A discrete or even consistent number of sub-levels.
As #Marc B's suggestion, a FORIEGN KEY with ON DELETE CASCADE would achieve this.
If you haven't one, you can add it now:
If there is a UNIQUE constraint on Name (I assume the PRIMARY key os ID), skip thi sstep. If there ism't one, create it:
ALTER TABLE tableX
ADD CONSTRAINT unique_Name
UNIQUE (Name) ;
If the previous step succeeded, add the FOREIGN KEY:
ALTER TABLE tableX
ADD CONSTRAINT fk_Name_ParentName
FOREIGN KEY (ParentName)
REFERENCES tableX (Name)
ON UPDATE CASCADE
ON DELETE CASCADE ;
If the previous step succeeded, you can now delete your rows with one statement:
DELETE
FROM tableX
WHERE ParentName = 'G_one' ;
This should result in: Y rows affected.
I can't test this, but I think something like this might work:
CREATE TRIGGER casc_del AFTER DELETE on tblName
FOR EACH ROW
DELETE FROM tblName
WHERE tblName.parent_name is not null
AND tblName.parent_name NOT IN (SELECT name FROM tblName)
More about triggers in MySQL can be found here. Note: this approach would only work in 5.02 or later.

how to delete records from several child tables in the same query

I ve got a database modelize like this,
One mother table let's call it table_mother, and severals child tables.
Relation beetween table_mother and childs is like this:
All tables childs have a foreign key kind of name as the id of the mother table (id_table_mother) (relationship is 1->n as id_table_mother is uniq and tbale child can get several entries for id_table_mother)
I would like to delete all records in childs table wich are related no more with the mother table, for now i try something like this
DELETE FROM tb_child_1,tb_child_2,tb_child_3
WHERE
tb_child_1.id_table_mother
AND tb_child_2.id_table_mother
AND tb_child_3.id_table_mother
NOT IN (SELECT id_table_mother FROM tb_table_mother);
Thx
edit : this is how I ended for now
delete from tb_child_1 where id_mother not in (select id_mother from tb_mother_table);
delete from tb_child_2 where id_mother not in (select id_mother from tb_mother_table);
any "global" solution ?
also my database is not innodb so I can 't go with foreigh keys and stuff
You have to build FOREIGN KEY Constraints to be performed on delete or update to know more about FOREIGN KEY Constraints visit http://dev.mysql.com/doc/refman/5.5/en/innodb-foreign-key-constraints.html
Write 3 queries like this one -
DELETE
tb_child_1
FROM
tb_table_mother
LEFT JOIN
tb_child_1
ON tb_table_mother.id_table_mother = tb_child_1.id_table_mother
WHERE
tb_child_1.id_table_mother IS NULL;

ON DUPLICATE KEY UPDATE ... with WHERE or subselection?

i am a bit concerned about one of my mysql queries... The following query receives a variable $DB_id... if a row with that primary key already exists the query performs an update.
$this->db->query(" INSERT INTO modules_text
( module_id,
module_content,
module_index
)
VALUES ( '{$DB_id}',
'{$content['text']}',
'{$index}'
)
ON DUPLICATE KEY
UPDATE module_content = '{$content['text']}',
module_index = '{$index}'
");
NOW THE THING THAT CONCERNS ME... There is no relation if the affected rows actually belong to the user. I would like to add a where statement to the UPDATE part or first make a subselecion of the rows which are permitted to be affected. SOmething like:
[...]
ON DUPLICATE KEY
UPDATE module_content = '{$content['text']}',
module_index = '{$index}'
WHERE module_post_id = '{$post]}'
Is this somehow possible... Until now i didnt find a solution... Any help would be very appreciated... THANKS A LOT!!!!!
Saludos Sacha!
This isn't how ON DUPLICATE KEY works. The update portion of the INSERT will only occur if there's a match for the UNIQUE key(s) or PRIMARY key for the table. (i.e.: The UNIQUE/PRIMARY key(s) are effectively the WHERE clause.)
See the full MySQL docs for more information.