MyTetra Share
Делитесь знаниями!
MySQL DELETE FROM with subquery as condition
Время создания: 13.07.2018 15:30
Текстовые метки: mysql delete subquery
Раздел: MySQL

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 (

SELECT DISTINCT(th1.tid)

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.


mysql sql subquery sql-delete in-subquery

shareimprove this question

edited Aug 10 '14 at 12:31


Sam

5,22183455

asked Dec 17 '10 at 14:15


mikl

11.5k135381

1

Attention: Good answer at the bottom stackoverflow.com/a/4471359/956397 simply add the table alias after DELETE t FROM table t ... – PiTheNumber Jul 24 '14 at 10:06

add a comment

7 Answers

active oldest votes

up vote

30

down vote

accepted

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

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;


DELETE FROM term_hierarchy AS th

WHERE th.parent = 1015 AND th.tid IN (select tid from term_hierarchy_backup);

shareimprove this answer

answered Dec 17 '10 at 14:23


ajreal

40k1070110

we are both right - see his comment to my answer below. Alias syntax and logic were both issues :) – JNK Dec 17 '10 at 14:51

Yeah, seems deleting via subquery is not currently possible in MySQL – thanks for taking a look at it :) – mikl Dec 17 '10 at 14:51

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. – malhal Jan 24 '12 at 20:02

You should add Index to term_hierarchy_backup.tid. – Roman Newaza Jan 2 '13 at 2:43

add a comment

up vote

195

down vote

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):


DELETE e.*

FROM tableE e

WHERE id IN (SELECT id

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:


DELETE e.*

FROM tableE e

WHERE id IN (SELECT id

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.


shareimprove this answer

edited Oct 22 '13 at 13:42


Benny Hill

5,08042750

answered Oct 19 '12 at 7:42


CodeReaper

3,93732647

7

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')". – Tilman Hausherr Mar 8 '13 at 11:28

3

Why does this work? This changes a lot for me, but moreover, it shouldn't work. It does work, but it shouldn't. – donatJ Apr 14 '14 at 21:53

1

unbelievable. this actually works! but you are not forced to alias the table with e... you can use any alias you want. – Andrei Sandulescu Apr 29 '14 at 13:37

1

Incredible! I'd really like to know why this works! – jakabadambalazs Jul 8 '14 at 21:00

4

@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. – Steve Almond Oct 6 '14 at 9:41

show 4 more comments

up vote

30

down vote

The alias should be included after the DELETE keyword:


DELETE th

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

);

shareimprove this answer

edited Oct 3 '12 at 2:04


ajreal

40k1070110

answered Dec 17 '10 at 14:24


James Wiseman

22.9k1274145

2

This is a good answer. Proper Aliasing will go a long way to solve problems similar to the original post. (like Mine.) – usumoio Dec 4 '13 at 21:02

add a comment

up vote

6

down vote

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.


shareimprove this answer

edited Oct 3 '12 at 2:03


ajreal

40k1070110

answered Dec 17 '10 at 14:20


JNK

48k597121

is not about alias, please check the OP again – ajreal Dec 17 '10 at 14:24

@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. – JNK Dec 17 '10 at 14:25

simply do this delete from your_table as t1 where t1.id in(select t2.id from your_table t2); what did you get ? – ajreal Dec 17 '10 at 14:27

4

The documentation clearly states; Currently, you cannot delete from a table and select from the same table in a subquery. dev.mysql.com/doc/refman/5.5/en/delete.html – Björn Dec 17 '10 at 14:36

1

you don't have to fix the alias, just don't specify target table for selecting in delete ...this is the real problem – ajreal Dec 17 '10 at 16:30

show 2 more comments

up vote

4

down vote

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

(

SELECT

`sl1`.`link_id`

FROM

(

SELECT


`sl2`.`link_id`


FROM

`secure_links` AS `sl2`

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


WHERE


`sl2`.`action` = 'something' AND

`conditions`.`ref` IS NULL

) AS `sl1`

)

Works for me.


shareimprove this answer

answered Aug 1 '14 at 11:12


Darren Edwards

411

add a comment

up vote

3

down vote

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)".?


DELETE T FROM Target AS T

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.


shareimprove this answer

edited May 23 '17 at 11:47


Community♦

11

answered Nov 11 '15 at 19:59


Jeff

312

add a comment

up vote

0

down vote

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.

 
MyTetra Share v.0.53
Яндекс индекс цитирования