MySQL错误1093 – 无法在FROM子句中为更新指定目标表

我在我的数据库中有一个表story_category与损坏的条目。 下一个查询返回损坏的条目:

 SELECT * FROM story_category WHERE category_id NOT IN ( SELECT DISTINCT category.id FROM category INNER JOIN story_category ON category_id=category.id); 

我试图删除它们执行:

 DELETE FROM story_category WHERE category_id NOT IN ( SELECT DISTINCT category.id FROM category INNER JOIN story_category ON category_id=category.id); 

但是我得到了下一个错误:

#1093 – 您无法在FROM子句中指定目标表'story_category'进行更新

我怎样才能克服呢?

更新:这个答案涵盖了一般的错误分类。 有关如何最好地处理OP的确切查询的更具体的答案,请参阅此问题的其他答案

在MySQL中,您不能修改您在SELECT部分​​中使用的同一个表。
此行为logging在: http : //dev.mysql.com/doc/refman/5.6/en/update.html

也许你可以join桌子本身

如果逻辑足够简单以重新塑造查询,则丢失子查询并使用适当的select标准将表join自己。 这将导致MySQL将这个表看作两个不同的东西,允许破坏性的更改继续。

 UPDATE tbl AS a INNER JOIN tbl AS b ON .... SET a.col = b.col 

或者,尝试将子查询嵌套到from子句中。

如果你绝对需要子查询,那么有一个解决方法,但是由于几个原因,包括性能,

 UPDATE tbl SET col = ( SELECT ... FROM (SELECT.... FROM) AS x); 

FROM子句中的嵌套子查询会创build一个隐式临时表 ,因此它不会被视为您正在更新的同一个表。

…但要小心查询优化器

但是,要注意,从MySQL 5.7.6开始,优化器可能会优化子查询,并且仍然会给出错误。 幸运的是,可以使用optimizer_switchvariablesclosures此行为; 尽pipe我不能推荐这样做,不仅仅是短期的修复,还是小的一次性任务。

 SET optimizer_switch = 'derived_merge=off'; 

感谢Peter V.Mørch在评论中的这个build议。

示例技术来自于最初在Nabble出版的 Baron Schwartz, 在这里转述并延伸。

NexusRex提供了一个非常好的解决scheme,用于从同一个表中删除连接。

如果你这样做:

 DELETE FROM story_category WHERE category_id NOT IN ( SELECT DISTINCT category.id AS cid FROM category INNER JOIN story_category ON category_id=category.id ) 

你会得到一个错误。

但是如果你在一个更多的select中包装条件

 DELETE FROM story_category WHERE category_id NOT IN ( SELECT cid FROM ( SELECT DISTINCT category.id AS cid FROM category INNER JOIN story_category ON category_id=category.id ) AS c ) 

它会做正确的事情!

你的子查询中的inner join是不必要的。 看起来您要删除story_categorycategory_id不在category表中的条目。

做这个:

 DELETE FROM story_category WHERE category_id NOT IN ( SELECT DISTINCT category.id FROM category); 

而不是:

 DELETE FROM story_category WHERE category_id NOT IN ( SELECT DISTINCT category.id FROM category INNER JOIN story_category ON category_id=category.id); 

最近我不得不更新logging在同一个表中,我做了如下:

 UPDATE skills AS s, (SELECT id FROM skills WHERE type = 'Programming') AS p SET s.type = 'Development' WHERE s.id = p.id; 
 DELETE FROM story_category WHERE category_id NOT IN ( SELECT cid FROM ( SELECT DISTINCT category.id AS cid FROM category INNER JOIN story_category ON category_id=category.id ) AS c ) 

这是我做了什么,如果它是一个表中≥> 1优先级列值,并在其WHERE子句使用同一个表上的子查询,以确保至less有一行包含优先级= 1(因为那是执行更新时要检查的条件):

 UPDATE My_Table SET Priority=Priority + 1 WHERE Priority >= 1 AND (SELECT TRUE FROM (SELECT * FROM My_Table WHERE Priority=1 LIMIT 1) as t); 

我知道这有点丑,但确实很好。

如果你不能这样做

 UPDATE table SET a=value WHERE x IN (SELECT x FROM table WHERE condition); 

因为它是同一张桌子,你可以欺骗和做:

 UPDATE table SET a=value WHERE x IN (SELECT * FROM (SELECT x FROM table WHERE condition) as t) 

[更新或删除或其他]

您可以将所需的行ID插入临时表中,然后删除在该表中find的所有行。

这可能是@Cheekysoft通过两步来完成的。

根据由@ CheekySoft链接的Mysql UPDATE语法 ,它在底部显示。

目前,您无法更新表并从子查询中的同一个表中进行select。

我想你是从store_category中删除,同时仍然从联盟中select。

如果有什么不行的话,当从前门进来的时候,走后门:

 drop table if exists apples; create table if not exists apples(variety char(10) primary key, price int); insert into apples values('fuji', 5), ('gala', 6); drop table if exists apples_new; create table if not exists apples_new like apples; insert into apples_new select * from apples; update apples_new set price = (select price from apples where variety = 'gala') where variety = 'fuji'; rename table apples to apples_orig; rename table apples_new to apples; drop table apples_orig; 

速度很快 数据越大越好。

尝试将Select语句的结果保存到单独的variables中,然后将其用于删除查询。

这个查询如何希望它有帮助

 DELETE FROM story_category LEFT JOIN (SELECT category.id FROM category) cat ON story_category.id = cat.id WHERE cat.id IS NULL