By mikl

2010-12-17 14:15:47 8 Comments

I am trying to do a query like this:

DELETE FROM term_hierarchy AS th
WHERE th.parent = 1015 AND th.tid IN (
    SELECT DISTINCT(th1.tid)
    FROM term_hierarchy AS th1
    INNER JOIN term_hierarchy AS th2 ON (th1.tid = th2.tid AND th2.parent != 1015)
    WHERE th1.parent = 1015

As you can probably tell, I want to delete the parent relation to 1015 if the same tid has other parents. However, that yields me a syntax error:

You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'AS th
WHERE th.parent = 1015 AND th.tid IN (
  FROM ter' at line 1

I have checked the documentation, and run the subquery by itself, and it all seems to check out. Can anyone figure out what's wrong here?

Update: As answered below, MySQL does not allow the table you're deleting from be used in a subquery for the condition.


@rc.adhikari 2019-02-11 14:06:25

@CodeReaper, @BennyHill: It works as expected.

However, I wonder the time complexity for having millions of rows in the table? Apparently, it took about 5ms to execute for having 5k records on a correctly indexed table.

My Query:

SET status = '1'
    SELECT id
    FROM (
      SELECT FROM clusters as c2
      WHERE c2.assign_to_user_id IS NOT NULL
        AND NOT IN (
         SELECT FROM clusters AS c1
           LEFT JOIN cluster_flags as cf on c1.last_flag_id =
           LEFT JOIN flag_types as ft on = cf.flag_type_id
         WHERE ft.slug = 'closed'
      ) x)```

Or is there something we can improve on my query above?

@TomoMiha 2017-12-25 16:05:46

If you want to do this with 2 queries, you can always do something similar to this:

1) grab ids from the table with:

SELECT group_concat(id) as csv_result FROM your_table WHERE whatever = 'test' ...

Then copy result with mouse/keyboard or programming language to XXX below:

2) DELETE FROM your_table WHERE id IN ( XXX )

Maybe you could do this in one query, but this is what I prefer.

@Jeff 2015-11-11 19:59:32

Isn't the "in" clause in the delete ... where, extremely inefficient, if there are going to be a large number of values returned from the subquery? Not sure why you would not just inner (or right) join back against the original table from the subquery on the ID to delete, rather than us the "in (subquery)".?

RIGHT JOIN (full subquery already listed for the in() clause in answers above) ` AS TT ON (TT.ID = T.ID)

And maybe it is answered in the "MySQL doesn't allow it", however, it is working fine for me PROVIDED I make sure to fully clarify what to delete (DELETE T FROM Target AS T). Delete with Join in MySQL clarifies the DELETE / JOIN issue.

@Darren Edwards 2014-08-01 11:12:45

I approached this in a slightly different way and it worked for me;

I needed to remove secure_links from my table that referenced the conditions table where there were no longer any condition rows left. A housekeeping script basically. This gave me the error - You cannot specify target table for delete.

So looking here for inspiration I came up with the below query and it works just fine. This is because it creates a temporary table sl1 that is used as the reference for the DELETE.

DELETE FROM `secure_links` WHERE `secure_links`.`link_id` IN 


                    `secure_links` AS `sl2` 
                    LEFT JOIN `conditions` ON `conditions`.`job` = `sl2`.`job` 


                    `sl2`.`action` = 'something' AND 
                    `conditions`.`ref` IS NULL 
                ) AS `sl1`

Works for me.

@CodeReaper 2012-10-19 07:42:39

For others that find this question looking to delete while using a subquery, I leave you this example for outsmarting MySQL (even if some people seem to think it cannot be done):

FROM tableE e
             FROM tableE
             WHERE arg = 1 AND foo = 'bar');

will give you an error:

ERROR 1093 (HY000): You can't specify target table 'e' for update in FROM clause

However this query:

FROM tableE e
             FROM (SELECT id
                   FROM tableE
                   WHERE arg = 1 AND foo = 'bar') x);

will work just fine:

Query OK, 1 row affected (3.91 sec)

Wrap your subquery up in an additional subquery (here named x) and MySQL will happily do what you ask.

@Tilman Hausherr 2013-03-08 11:28:26

Took some time but I got it to work. Important: 1) The first table must be aliased as shown here with "e", 2) the "x" at the end is not a placeholder, it is the alias for the temp table produced by the subquery "(SELECT id FROM tableE WHERE arg = 1 AND foo = 'bar')".

@donatJ 2014-04-14 21:53:07

Why does this work? This changes a lot for me, but moreover, it shouldn't work. It does work, but it shouldn't.

@Andrei Sandulescu 2014-04-29 13:37:00

unbelievable. this actually works! but you are not forced to alias the table with e... you can use any alias you want.

@jakabadambalazs 2014-07-08 21:00:25

Incredible! I'd really like to know why this works!

@CodeReaper 2014-07-09 07:24:52

@jakabadambalazs My reasoning when coming up with it, was that the subquery starting with "SELECT id" finishes and returns a list of ids and therefore releases the lock of the table you want to delete from.

@Steve Almond 2014-10-06 09:41:11

@jakabadambalazs: We can't use the same table (e) in a DELETE and in its sub-SELECT. We can, however use a sub-sub-SELECT to create a temporary table (x), and use that for the sub-SELECT.

@Sauron 2014-10-24 20:35:18

@CodeReaper Correct me if I'm wrong, but do you think subquery failed because you did not put an alias on the first subquery? at line WHERE arg = 1 AND foo = 'bar'); should be WHERE arg = 1 AND foo = 'bar') 'alias letter';

@txyoji 2016-09-20 22:04:31

Steve Almond is correct. It creates a temp table. Run an explain plan on the delete statement and you'll see what I mean.

@Terry Lin 2017-02-12 17:31:47

Incredible, it does work in my case.. even I don't know why

@Smith 2018-12-12 09:14:15

Correct - it works because the derived table is executed before the parent query - therefore there's no conflict in reading the table

@James Wiseman 2010-12-17 14:24:35

The alias should be included after the DELETE keyword:

FROM term_hierarchy AS th
WHERE th.parent = 1015 AND th.tid IN 
    SELECT DISTINCT(th1.tid)
    FROM term_hierarchy AS th1
    INNER JOIN term_hierarchy AS th2 ON (th1.tid = th2.tid AND th2.parent != 1015)
    WHERE th1.parent = 1015

@usumoio 2013-12-04 21:02:33

This is a good answer. Proper Aliasing will go a long way to solve problems similar to the original post. (like Mine.)

@JNK 2010-12-17 14:20:13

You need to refer to the alias again in the delete statement, like:

DELETE th FROM term_hierarchy AS th

As outlined here in MySQL docs.

@ajreal 2010-12-17 14:24:20

is not about alias, please check the OP again

@JNK 2010-12-17 14:25:19

@ajreal - I did, and please notice the error begins at the alias definition, and MySQL documentation explicitly states you need to use the alias in the DELETE statement as well as the FROM clause. Thanks for the downvote, though.

@ajreal 2010-12-17 14:27:14

simply do this delete from your_table as t1 where in(select from your_table t2); what did you get ?

@Björn 2010-12-17 14:36:44

The documentation clearly states; Currently, you cannot delete from a table and select from the same table in a subquery.

@mikl 2010-12-17 14:49:33

Ah, as Björn says, it is impossible :( Fixing the alias thing just gives a different error: "You can't specify target table 'th' for update in FROM clause"

@JNK 2010-12-17 14:50:41

@mikl - Then you had two errors :) Fix the alias and use ajreal's workaround.

@ajreal 2010-12-17 16:30:01

you don't have to fix the alias, just don't specify target table for selecting in delete ...this is the real problem

@ajreal 2010-12-17 14:23:32

You cannot specify target table for delete.

A workaround

create table term_hierarchy_backup (tid int(10)); <- check data type

insert into term_hierarchy_backup 
FROM term_hierarchy AS th1
INNER JOIN term_hierarchy AS th2 ON (th1.tid = th2.tid AND th2.parent != 1015)
WHERE th1.parent = 1015;

DELETE FROM term_hierarchy AS th
WHERE th.parent = 1015 AND th.tid IN (select tid from term_hierarchy_backup);

@JNK 2010-12-17 14:51:27

we are both right - see his comment to my answer below. Alias syntax and logic were both issues :)

@mikl 2010-12-17 14:51:44

Yeah, seems deleting via subquery is not currently possible in MySQL – thanks for taking a look at it :)

@malhal 2012-01-24 20:02:55

doesn't the "DELETE FROM term_hierarchy AS th" in that last line have the same problem? I get a syntax error the same as the OP.

@Roman Newaza 2013-01-02 02:43:23

You should add Index to term_hierarchy_backup.tid.

@alpham8 2019-08-29 06:50:23

I am able to verify that, that it is neither possible in 2019 on MariaDB 10.3.14 or MySQL Community Server 5.7.27

Related Questions

Sponsored Content

37 Answered Questions

[SOLVED] Should I use the datetime or timestamp data type in MySQL?

34 Answered Questions

[SOLVED] Reference - What does this error mean in PHP?

15 Answered Questions

[SOLVED] How to Delete using INNER JOIN with SQL Server?

45 Answered Questions

[SOLVED] How do I import an SQL file using the command line in MySQL?

15 Answered Questions

[SOLVED] MySQL Error 1093 - Can't specify target table for update in FROM clause

33 Answered Questions

[SOLVED] How do I UPDATE from a SELECT in SQL Server?

5 Answered Questions

[SOLVED] Deleting rows with MySQL LEFT JOIN

10 Answered Questions

[SOLVED] How to remove constraints from my MySQL table?

2 Answered Questions


  • 2012-08-26 01:26:30
  • Lenin Raj Rajasekaran
  • 555498 View
  • 235 Score
  • 2 Answer
  • Tags:   mysql sql

6 Answered Questions

[SOLVED] How to delete from multiple tables in MySQL?

Sponsored Content