46

I have 4 tables that stores different information about a user in each. Each table has a field with user_id to identify which row belongs to which user. If I want to delete the user is this the best way to delete that users information from multiple tables? My objective is to do it in one query.

Query:

"DELETE FROM table1 WHERE user_id='$user_id';
DELETE FROM table2 WHERE user_id='$user_id';
DELETE FROM table3 WHERE user_id='$user_id';
DELETE FROM table4 WHERE user_id='$user_id';";
3
  • 2
    Why would you want to do this in one query? Commented Jan 29, 2011 at 22:45
  • 3
    Seconded. The correct answer is, "why"? Commented Jan 29, 2011 at 22:46
  • 2
    @diagonalbatman The idea is to reduce the number of database calls from within the application, which are expensive. If user_id is indexed, then combining these statements with a JOIN is more efficient. It's the difference between buying four milks at once versus driving four times to the grocery store for one milk. If the OP's queries are within an application (and not at a console), and user_id is indexed, then a JOIN method is better. If he's at the console, then it doesn't much matter, but it's still a good question. Commented Apr 23, 2020 at 21:22

9 Answers 9

60

Apparently, it is possible. From the manual:

You can specify multiple tables in a DELETE statement to delete rows from one or more tables depending on the particular condition in the WHERE clause. However, you cannot use ORDER BY or LIMIT in a multiple-table DELETE. The table_references clause lists the tables involved in the join. Its syntax is described in Section 12.2.8.1, “JOIN Syntax”.

The example in the manual is:

DELETE t1, t2 FROM t1 INNER JOIN t2 INNER JOIN t3
WHERE t1.id=t2.id AND t2.id=t3.id;

should be applicable 1:1.

Sign up to request clarification or add additional context in comments.

7 Comments

The explicit join syntax would be: DELETE t1, t2 FROM t1 INNER JOIN t2 ON t1.id=t2.id INNER JOIN t3 ON t2.id=t3.id;
Ran into an issue here (and with Rodel's answer).. if the same user_id doesn't exist in all tables, none of the rows are deleted, whereas in the question, those queries would delete all rows in all tables for a certain user.
@LGT simply change the INNER JOIN to some other type of JOIN as appropriate
This query is for three tables, How can I do that for two tables?
I think the query assumes that you need all three joins to match all you need. But since the DELETE clause only specifies t1, t2 only those two tables will be affected.
|
41

You can define foreign key constraints on the tables with ON DELETE CASCADE option.

Then deleting the record from parent table removes the records from child tables.

Check this link : https://dev.mysql.com/doc/refman/5.7/en/create-table-foreign-keys.html

6 Comments

+1 This is the way to do it. Even though this isn't answering the question that was asked it is answering the question that should have been asked, which is how do I maintain data integrity when removing records from a table.
It fails to mention that foreign keys are only available with some storage engines, and does not answer the question.
It's also not so helpful if you're not deleting the main record (i.e. keeping data in some content table but resetting its mappings by deleting all references in multiple many-to-many relational tables - my particular use case).
This is exactly what I was asking ...
Note that changes as a result of a CASCADE do not fire TRIGGERs. This means that if you have a TRIGGER on table A, and a FOREIGN KEY to a column in table B, and you do e.g. a DELETE in table B that CASCADEs to table A, the trigger on table A is not triggered. This can lead to severe bugs such as data loss, or ruining your data integrity. Do not use CASCADE with FOREIGN KEYs for this very reason, use RESTRICT instead (which is default if nothing else is specified).
|
38

You can also use following query :

DELETE FROM Student, Enrollment USING Student INNER JOIN Enrollment ON Student.studentId = Enrollment.studentId WHERE Student.studentId= 51;

2 Comments

Thanks. Unlike the other answers, this was helpful. (I don't have access to InnoDB.)
This works if you have the record in both tables. If it is missing from one table, nothing is deleted in the other table.
19

A join statement is unnecessarily complicated in this situation. The original question only deals with deleting records for a given user from multiple tables at the same time. Intuitively, you might expect something like this to work:

DELETE FROM table1,table2,table3,table4 WHERE user_id='$user_id'

Of course, it doesn't. But rather than writing multiple statements (redundant and inefficient), using joins (difficult for novices), or foreign keys (even more difficult for novices and not available in all engines or existing datasets) you could simplify your code with a LOOP!

As a basic example using PHP (where $db is your connection handle):

$tables = array("table1","table2","table3","table4");
foreach($tables as $table) {
  $query = "DELETE FROM $table WHERE user_id='$user_id'";
  mysqli_query($db,$query);
}

Hope this helps someone!

5 Comments

While possibly a good solution, the original post doesn't mention or tag PHP.
True, but I was only using PHP to illustrate the method. The equivalent can be achieved with other languages as well.
BEWARE, I was using this approach only to find that deleting like this in a loop with 6-7 tables is very processor incentive. In my case it actually crashed my server !
@jahajee.com BEWARE what, exactly? You'd only be running seven simple queries. If you had one million rows in all seven tables, and user_id wasn't even indexed, this code should still not take that long.
Yeah, this method will certainly not crash a server. Something else did that.
10

from two tables with foreign key you can try this Query:

DELETE T1, T2
FROM T1
INNER JOIN T2 ON T1.key = T2.key
WHERE condition

Comments

8

You can use following query to delete rows from multiple tables,

DELETE table1, table2, table3 FROM table1 INNER JOIN table2 INNER JOIN table3 WHERE table1.userid = table2.userid AND table2.userid = table3.userid AND table1.userid=3

1 Comment

This answser should be checked in green ;)
5

The documentation for DELETE tells you the multi-table syntax.

DELETE [LOW_PRIORITY] [QUICK] [IGNORE]
    tbl_name[.*] [, tbl_name[.*]] ...
    FROM table_references
    [WHERE where_condition]

Or:

DELETE [LOW_PRIORITY] [QUICK] [IGNORE]
    FROM tbl_name[.*] [, tbl_name[.*]] ...
    USING table_references
    [WHERE where_condition]

2 Comments

What is mean of "LOW_PRIORITY"? It means if I write DELETE table1, table2 FROM ... first the rows of table1 will delete and then the rows of table2 ?
@Sajad: There is a link to the documentation starting at the second word of my answer. Click on it, and read.
0

usually, i would expect this as a 'cascading delete' enforced in a trigger, you would only need to delete the main record, then all the depepndent records would be deleted by the trigger logic.

this logic would be similar to what you have written.

Comments

0

Normally you can't DELETE from multiple tables at once, unless you'll use JOINs as shown in other answers.

However if all yours tables starts with certain name, then this query will generate query which would do that task:

SELECT CONCAT('DELETE FROM ', GROUP_CONCAT(TABLE_NAME SEPARATOR ' WHERE user_id=123;DELETE FROM ') , 'FROM table1;' ) AS statement FROM information_schema.TABLES WHERE TABLE_NAME LIKE 'table%'

then pipe it (in shell) into mysql command for execution.

For example it'll generate something like:

DELETE FROM table1 WHERE user_id=123;
DELETE FROM table2 WHERE user_id=123;
DELETE FROM table3 WHERE user_id=123;

More shell oriented example would be:

echo "SHOW TABLES LIKE 'table%'" | mysql | tail -n +2 | xargs -L1 -I% echo "DELETE FROM % WHERE user_id=123;" | mysql -v

If you want to use only MySQL for that, you can think of more advanced query, such as this:

SET @TABLES = (SELECT GROUP_CONCAT(TABLE_NAME) FROM information_schema.TABLES WHERE TABLE_NAME LIKE 'table%');
PREPARE drop_statement FROM 'DELETE FROM @tables';
EXECUTE drop_statement USING @TABLES;
DEALLOCATE PREPARE drop_statement;

The above example is based on: MySQL – Delete/Drop all tables with specific prefix.

1 Comment

I haven't tried it. But I like the way you did it. Cool !!

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.