Deleting related records in MySQL - php

I have two MySQL (MyISAM) tables:
Posts: PostID(primary key), post_text, post_date, etc.
Comments: CommentID(primary key), comment_text, comment_date, etc.
I want to delete all the comments in the "Comments" table belonging to a particular post, when the corresponding post record is deleted from the "Posts" table.
I know this can be achieved using cascaded delete with InnoDB (by setting up foreign keys). But how would I do it in MyISAM using PHP?

DELETE
Posts,
Comments
FROM Posts
INNER JOIN Comments ON
Posts.PostID = Comments.PostID
WHERE Posts.PostID = $post_id;
Assuming your Comments table has a field PostID, which designates the Post to which a Comment belongs to.

Even without enforceable foreign keys, the method to do the deletion is still the same. Assuming you have a column like post_id in your Comments table
DELETE FROM Comments
WHERE post_id = [Whatever Id];
DELETE FROM Posts
WHERE PostID = [Whatever Id];
What you really lose with MyISAM is the ability to execute these two queries within a transaction.

I've never tried it, but you could set up a trigger to do cascading deletes (if you are using >=5.0)
DELIMITER $$
CREATE TRIGGER Posts_AD AFTER DELETE ON Posts
FOR EACH ROW
BEGIN
DELETE FROM Comments WHERE post_id = OLD.PostID;
END $$
DELIMITER ;

Related

When I delete from the students table, it will also delete the items on voters table

I am new and don't know how to code well, but I want to modify the system.
TARGET: When I delete the 'id' from the students table it will also delete 'userid' from the voters table.
SCREENSHOT OF DB:
students TABLE
voters TABLE
HERE IS CODE I AM USING. (THIS CODE ONLY DELETE THE ROWS ON students TABLE)
I have tried using another query but nothing happened. Can someone please fix the code for me? I am new to this.
<?php ob_start();
session_start();
if (!isset($_SESSION['id'])){
header("location:../login.php");
}
?>
<?php
include('../connect.php');
$id=$_GET['id'];
$del = mysqli_query($connection,"DELETE FROM students WHERE id='$id'");
?>
This is a desired functionality when you are using any RDBMS. i.e. when there are 2 tables with a foreign key relationship between them and the foreign key of the 1st table is a Primary key of the 2nd table. Then deleting the 1st tables record will be triggering the deletion of the record associated with it in the 2nd table.
This is called a cascade delete which is much better explained with the below definition.
A foreign key with cascade delete means that if a record in the parent table is deleted, then the corresponding records in the child table will automatically be deleted. This is called a cascade delete in SQL Server.
MySQL:
You can delete with a JOIN like this:
DELETE users
FROM users
INNER JOIN voters
ON users.id = voters.userid
WHERE users.name = 'Jordan Santos';
See this SQL fiddle for an example with data. (You can comment out the DELETE statement with a # to see the query results without deleting anything.)
Postgres:
You could use two Common Table Expressions (i.e., WITH clauses) to do the deletions in each table:
WITH user_deletion AS (
-- this deletes the user based on username
DELETE
FROM users u
WHERE username='Dad'
RETURNING id, username
),
vote_deletion AS (
-- this gets the deleted user_id from above and deletes the corresponding vote(s)
DELETE
FROM votes
WHERE user_id = (SELECT id FROM user_deletion)
RETURNING vote_id, user_id, vote
)
-- this runs the DELETE statements in the clauses above
SELECT udel.*, vdel.*
FROM user_deletion udel
INNER JOIN vote_deletion vdel
ON udel.id = vdel.user_id;
See this SQL Fiddle for a Postgres example with data, showing results both before and after the deletion.

Delete multiple rows from multiple tables in mysql using single value

I have a number of mysql tables with different table structures and all they have the followings table names and fieldnames (the ones of the left are table names and on the right are field names)
I want to be able to delete the values of the rows using a single variable (example $id = somename) in a single query
user id,
user_image user
user_interest user
user_lang id
user_login user
user_personal user
user_prefer user
user_reviewuser
user_role user_id
user_translang user
user_translate user
user_web id
Also, a particular userid may not be present across all tables.
I am not sure at all on how to delete them all at once. Any tips would be appreciated, i looked at a couploe of similar questions but couldn't find a proper answer.
You want to create a foreign key constraint, and specify "ON DELETE CASCADE". You'll need this for each of your tables that has a foreign key to user. For example,
ALTER TABLE user_image
ADD CONSTRAINT fk_user_image_user FOREIGN KEY (user)
REFERENCES user(id)
ON DELETE CASCADE;
You can use the multi-table DELETE syntax. You need to use a LEFT JOIN in case any of the related tables do not have a corresponding row.
DELETE user, user_image, user_interest, ...
FROM user
LEFT JOIN user_image ON user.id = user_image.user
LEFT JOIN user_interest ON user.id = user_interest.user
...
WHERE user.id = $id
DEMO
However, if you relate the tables using a foreign key constraint, with ON DELETE CASCADE, you can just delete the row from the user table, and all the related rows will be deleted.

Delete all foreign key data on delete of primary or vice-a-versa

I have table structure like this:
PrimaryTable -> p_id Here p_id is primary
SecondoryTable -> s_id p_id Here p_id is a foreign key
ThirdTable -> t_id s_id Here s_id is foreign key
FourthTable -> f_id t_id Here t_id is foreign key
So I am deleting one of my p_id from PrimaryTable and want that its SecondoryTable data should also get delete AND ThirdTable data should be deleted with reference to SecondoryTable and FourthTable data should be deleted with reference to ThirdTable
I know i can write Delete query from bottom to top, but how to do for so many levels like this??
I found this but not sure on howto: https://stackoverflow.com/a/9847308/1182021
Because its four level hierarchy i am confused.
EDIT1:
What if I want to delete Primary on Delete of Child
Kindly suggest.
As per OP's request, this is an answer for the case when the user wants to delete the row from the parent table when a row is deleted from the child table. The case for recursively deleting all the children when a parent is deleted is working using MySQL ON DELETE CASCADE option.
The 4 tables would be table1, table2, table3 & table4.
If the user wants to delete a row in table2 and also the corresponding row in table1 (parent of table2) then in PHP:
// t2_delete_row_id is the id of the table 2 row to be deleted
// get the the parent of table2
$sql_get_parent = "select p_id from table2 where s_id = 't2_delete_row_id '";
// execute this query using MySQLi/PDO to get id of the parent row to be deleted
// assuming that id is t1_parent_row_id
// now delete the row from table 2:
// note that because of the foreign key constraints,
// corresponding rows from table3 and table4 would also be deleted
$sql_delete_child = "delete from table2 where s_id = 't2_delete_row_id'";
if (mysqli_query($sql_delete_child)){
// delete the parent row
$sql_delete_parent = "delete from table1 where p_id = 't1_parent_row_id'";
}
this logic can be extended so that on deleting table3 row, corresponding parent(table2) and "grand-parent" (table1) rows would be deleted as well. A bit of recursion might be needed for that case. And this will of course delete the child rows in table4 because of the foreign key constraint.
If you are not able to use FOREIGN KEYS (ie using MyISAM tables) I would create a TRIGGER for this. Example for first one below ... you will need to make one for each table that's cascading.
DELIMITER //
CREATE TRIGGER `pDeleteTrigger` BEFORE DELETE ON `PrimaryTable`
FOR EACH ROW BEGIN
DELETE FROM `SecondoryTable` WHERE NEW.`p_id` = `SecondoryTable`.`p_id`
END
//
DELIMITER ;
I have two approachs in my mind (if your language is Tsql)
1.- Store procedure
The idea is have a procedure "spDelete_PrimaryTable", so that you can delete the registers in the four tables by writinf something in tsql like:
exec spDelete_PrimaryTable
#p_id= 25 /* (25 or watever p_id of primary table you want to delete)*/
(yes you can call it from vb.net or watever you want to.)
the code would be something like:
use [your_database]
CREATE PROCEDURE [dbo].[spDelete_PrimaryTable]
#p_id nvarchar(MAX)
AS
begin
SET NOCOUNT ON;
delete from FourthTable where t_id in (
select ThirdTable.t_id
from ThirdTable inner join SecondoryTable on ThirdTable.s_id = SecondoryTable.s_id
where SecondoryTable.p_id = #p_id
)
go
delete from ThirdTable where s_id in (
select SecondoryTable.s_id
where SecondoryTable.p_id = #p_id
)
go
/*Lol, I forgot to eliminate from the "SecondoryTable" */
delete from SecondoryTable.s_id
where SecondoryTable.p_id = #p_id
go
delete from PrimaryTable where p_id = #p_id
go
END
GO
2.- Triggers
seems like "Christopher Morrissey" have already posted that while i was editing this answer XP

mysql DELETE with field check from another table

Good morning all, happy thursday morning. I wish I could have done this by myself but since I'm not a master in MySQL statements (yet) and I got lost in this DELETE query, here it goes...
I have to do a simple DELETE query like this, (deleting a comment by its id)
DELETE FROM mya_news_comments WHERE comment_id='".$_GET['comment_id']."'";
but at the same time, to prevent people deleting comments throughout the website
i need to ensure that the person deleting this comment is who it is supposed to be (in our case, an artist).
I have another table mya_news which has among the fields news_id, artist_id
In mya_news_comments I also have a field called news_id
So I need to check that I delete the comment_id of the particular artist, not of other artist.
Basically i need to cross-check if the news_id field from mya_news_comments checks out with a field with same news_id from mya_news, and artist_id from mya_news is equal to $_id (which holds my artist_id)
I'm really stuck here. I'd be glad to give more details if needed.
Thanks.
DELETE mya_news_comments
FROM mya_news_comments
WHERE mya_news_comments.comment_id = (SELECT [another_table].comment_id WHERE [cond])
AND mya_news.artist_id = (SELECT [another_table].artist_id WHERE [cond]);
You can join tables in DELETE statements just like you can in SELECT statements:
DELETE mya_news_comments
FROM mya_news_comments JOIN mya_news USING (news_id)
WHERE mya_news_comments.comment_id = ?
AND mya_news.artist_id = ?

Multiple insert queries

I have three tables that essentially cascade down, like:
topic
section (references topic id)
subsection (references topic id and section id)
Whats the best method of writing mysql statements to create the initial topic/section/subsection so I can grab the id's (auto_incremented) of the newly created rows and use them to insert them into the second two?
edit
I'm using phpbb3, dunno if that makes a huge difference, but I normally use the $db-sql_query() function
From the parent, down the line.
Then you can use either LAST_INSERT_ID(), or INSERT in the SELECT:
INSERT INTO TOPIC
(topic_id, topic)
VALUES (DEFAULT, $topic);
INSERT INTO SECTION
(topic_id, section)
SELECT topic_id, $section
FROM TOPIC
WHERE topic = $topic
INSERT INTO SUBSECTION
(section_id, topic_id, subsection)
SELECT section_id, topic_id
FROM SECTION
WHERE section = $section
This example assumes that TOPIC.topic_id, SECTION.section_id, and SUBSECTION are auto_increment, primary key columns.
You can use mysql_insert_id() to get the last insert ID. see reference for more details.
As far as I understand, there's only one way, which is top-down.
To add a subsection to a section, you must have had a section already inserted.
To add a topic to a subsection, make sure you added the subsection first.
On the way, you keep track of the last inserted ID (if you just created it) to give it to the next entity down the line.

Categories