44

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';";
Jason
  • 2,687
  • 3
  • 29
  • 40
  • 2
    Why would you want to do this in one query? – diagonalbatman Jan 29 '11 at 22:45
  • 3
    Seconded. The correct answer is, "why"? – Lightness Races in Orbit Jan 29 '11 at 22:46
  • 1
    @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. –  Apr 23 '20 at 21:22

9 Answers9

57

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.

Pekka
  • 442,112
  • 142
  • 972
  • 1,088
  • 3
    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;` – juergen d Jul 28 '14 at 18:44
  • 3
    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 Aug 03 '14 at 21:25
  • 1
    @LGT simply change the `INNER JOIN` to some other type of JOIN as appropriate – Martin Aug 18 '15 at 21:34
  • This query is for three tables, How can I do that for two tables? – Shafizadeh Sep 27 '15 at 13:19
  • 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. – rodrigo-silveira Aug 01 '16 at 17:48
  • @Pekka, What should I do when I've large number of data in one table – er.irfankhan11 Jun 27 '19 at 10:51
  • Just to add - INNER JOIN will only delete records if the id exists in every table referenced. LEFT JOIN would delete from T1 even if the id doesnt exist in T2. Play with joins to get the desired outcome. – MrrMan Jun 14 '20 at 17:34
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 : http://dev.mysql.com/doc/refman/5.5/en/innodb-foreign-key-constraints.html

Richard Harrison
  • 19,247
  • 4
  • 40
  • 67
Chandu
  • 81,493
  • 19
  • 133
  • 134
  • 8
    +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. – Richard Harrison Jan 29 '11 at 22:50
  • 2
    It fails to mention that foreign keys are only available with some storage engines, and does not answer the question. – Lightness Races in Orbit Feb 14 '11 at 10:22
  • 4
    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). – HonoredMule Nov 28 '13 at 19:03
  • This is exactly what I was asking ... – Adelin Oct 12 '15 at 12:02
  • Note that changes as a result of a `CASCADE` do not fire `TRIGGER`s. 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 `CASCADE`s 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 KEY`s for this very reason, use `RESTRICT` instead (which is default if nothing else is specified). – Adrian Wiik Nov 06 '20 at 09:16
  • @Chandu the link is outdated. May you please update it? thanks. – Texv May 06 '23 at 09:05
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;

Abhijeet Kasurde
  • 3,937
  • 1
  • 24
  • 33
Rodel Sarate
  • 819
  • 3
  • 11
  • 11
18

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!

JoshR
  • 461
  • 3
  • 9
  • 1
    While possibly a good solution, the original post doesn't mention or tag PHP. – jlemley Jul 06 '15 at 18:56
  • 3
    True, but I was only using PHP to illustrate the method. The equivalent can be achieved with other languages as well. – JoshR Jul 06 '15 at 20:09
  • 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 Jun 18 '17 at 03:02
  • @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. –  Apr 23 '20 at 20:59
  • Yeah, this method will certainly *not* crash a server. Something else did that. – JoshR Jun 17 '20 at 00:19
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
iamsankalp89
  • 4,607
  • 2
  • 15
  • 36
Niraj patel
  • 525
  • 4
  • 12
7

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

Abhijeet Kasurde
  • 3,937
  • 1
  • 24
  • 33
4

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]
Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
1

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.

kenorb
  • 155,785
  • 88
  • 678
  • 743
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.

Randy
  • 16,480
  • 1
  • 37
  • 55