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

问题描述 投票:524回答:14

我的数据库中有一个表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'

我怎么能克服这个?

mysql subquery sql-delete mysql-error-1093
14个回答
656
投票

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

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

也许你可以加入桌子

如果逻辑足够简单以重新构造查询,则使用适当的选择条件丢失子查询并将表连接到自身。这将导致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子句中的嵌套子查询创建一个隐式临时表,因此它不会计入您正在更新的同一个表。

...但请注意查询优化器

但是,请注意,从MySQL 5.7.6开始,优化器可能会优化子查询,但仍然会给出错误。幸运的是,optimizer_switch变量可用于关闭此行为;虽然我不建议将其作为短期修复或小型一次性任务。

SET optimizer_switch = 'derived_merge=off';

感谢Peter V. Mørch在评论中提出这一建议。

示例技术来自Baron Schwartz,originally published at Nabble,在此进行了解释和扩展。


2
投票

如果有什么东西不起作用,当从前门进来时,请带上后门:


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

它很快。数据越大越好。


2
投票

最简单的方法是在子查询中引用父查询表时使用表别名。

示例:

 the Mysql UPDATE Syntax

将其更改为:

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;

2
投票

试试这个

insert into xxx_tab (trans_id) values ((select max(trans_id)+1 from xxx_tab));

1
投票

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


1
投票

这个查询怎么样希望它有所帮助

insert into xxx_tab (trans_id) values ((select max(P.trans_id)+1 from xxx_tab P));

257
投票

qazxsw poi提供了一个qazxsw poi,用于从同一个表中加入删除。

如果你这样做:

NexusRex

你会得到一个错误。

但是如果你将条件换成另一个选择:

very good solution

它会做正确的事!!

说明:查询优化器为第一个查询执行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 ) (导致它因错误而失败),但第二个查询不符合派生合并优化的条件。因此,优化器必须首先执行子查询。


102
投票

您的子查询中的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 ) 是不必要的。看起来你想要删除derived merge optimizationinner join不在story_category表中的条目。

做这个:

category_id

而不是:

category

89
投票

最近我不得不在同一个表中更新记录,如下所示:

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

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

21
投票

如果你做不到

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
)

[更新或删除或其他]


12
投票

如果在表中使用> = 1并且在WHERE子句中使用同一个表上的子查询来更新优先级列值,则执行此操作以确保至少有一行包含Priority = 1(因为那是执行更新时要检查的条件):

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

我知道它有点难看,但确实很好。


5
投票

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

这可能是@Cheekysoft分两步做的意思。


4
投票

根据@CheekySoft链接的UPDATE table SET a=value WHERE x IN (SELECT * FROM (SELECT x FROM table WHERE condition) as t) ,它在底部说。

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

我猜你正在从store_category中删除,同时仍在联盟中选择它。

© www.soinside.com 2019 - 2024. All rights reserved.