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

MySQL错误1093-无法在FROM子句中指定更新的目标表,mysql,subquery,sql-delete,mysql-error-1093,Mysql,Subquery,Sql Delete,Mysql Error 1093,我的数据库中有一个包含损坏项的表story_类别。下一个查询将返回损坏的条目: 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

我的数据库中有一个包含损坏项的表story_类别。下一个查询将返回损坏的条目:

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子句中为更新指定目标表“故事\类别”

如何克服此问题?

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

在MySQL中,您不能修改SELECT部件中使用的同一个表。 这种行为记录在:

也许你可以把桌子连在一起

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

。。。但要注意查询优化程序

但是,请注意,从开始到结束,优化程序可能会优化子查询,但仍然会给出错误。幸运的是,优化器_开关变量可用于关闭此行为;尽管我不能推荐这样做,因为这只是一个短期修复,或者是一次过的小任务

SET optimizer_switch = 'derived_merge=off';
感谢您在评论中的建议


示例技术来自Baron Schwartz,在这里进行了解释和扩展。

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


这可能就是@Cheekysoft分两步操作的意思。

如果有东西不起作用,从前门进来,然后从后门走:

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;
很快。数据越大越好。

子查询中的内部联接是不必要的。似乎要删除类别id不在类别表中的story_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);

如果优先级列值在表中大于等于1,则在其WHERE子句中使用同一表上的子查询将优先级列值更新为1,以确保至少有一行包含优先级=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);
我知道这有点难看,但它确实工作得很好。

提供了一个从同一个表中删除with join的方法

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
)
如果您这样做:

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
)
您将得到一个错误

但如果将条件包装在一个或多个选项中,请选择:

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
)
它会做正确的事情


说明:查询优化器对第一个查询执行了一次优化,导致其失败并出现错误,但第二个查询不符合派生合并优化的条件。因此,优化器必须首先执行子查询。

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

UPDATE skills AS s, (SELECT id  FROM skills WHERE type = 'Programming') AS p
SET s.type = 'Development' 
WHERE s.id = p.id;
根据@CheekySoft的链接,它在底部写着

当前,无法更新表并在子查询中从同一表中进行选择


我猜您正在从store_类别中删除,但仍在联合中从中进行选择。

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

如果您不能这样做

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)

[更新或删除或其他内容]

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

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

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

例如:

insert into xxx_tab (trans_id) values ((select max(trans_id)+1 from xxx_tab));
将其更改为:

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

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

对于OP试图实现的特定查询,理想且最有效的方法是根本不使用子查询

以下是OP两个查询的左连接版本:

选择s.* 来自story_类别s 左连接类别c 在c.id=s.category\u id上 其中c.id为空; 注意:DELETE s将删除操作限制在story_类别表中

删除 来自story_类别s 左连接类别c 在c.id=s.category\u id上 其中c.id为空;
就问题而言,您希望删除类别中不存在的story_类别中的行

以下是用于标识要删除的行的原始查询:

SELECT * 
FROM  story_category 
WHERE category_id NOT IN (
    SELECT DISTINCT category.id 
    FROM category INNER JOIN 
       story_category ON category_id=category.id
);
将NOT IN与联接原始表的子查询组合在一起似乎非常复杂。这可以通过不存在和相关子查询以更直接的方式表示:

select sc.*
from story_category sc
where not exists (select 1 from category c where c.id = sc.category_id);
现在很容易将其转换为delete语句:

delete from story_category
where not exists (select 1 from category c where c.id = story_category.category_id);    
这个查询可以在任何MySQL版本上运行,也可以在我所知道的大多数其他数据库中运行

:


这应该是最好的答案!也许删除

首先,而不是。我认为在这里没有必要使用DISTINCT-为了更好的性能;。我一定是疯了。答案与原文所述相同。这也是我的答案。不要在ID列中的任何位置,这样就不需要子查询主表。@JeffLowery-这里的第一个代码块就是答案;这是问题中的第二个代码块。@anonymous_reviewer:如果对某人的评论给出[-1]甚至[+1],请同时说明你为什么给出它。谢谢-1因为这是不正确的。您不能修改SELECT语句中使用的同一个表。@Chris我已经在MySQL上验证了它,它对我来说很好,所以我请求您在您的末尾验证它,然后声明它是正确的或不正确的。谢谢在这一页的底部写着“目前,您无法更新一个表并在子查询中从同一个表中进行选择”-我在很多情况下都经历过这种情况@Chris我知道这一点,但有一个解决办法,这正是我试图用“更新”查询显示的,相信我,它工作得很好。我认为您根本没有尝试验证我的查询。我对这个答案投了赞成票,因为我必须删除项目,无法从另一个表中获取信息,必须从同一个表中进行子查询。由于这是在谷歌搜索我得到的错误时在顶部弹出的内容,因此这将是最适合我和许多人的答案,他们试图在从同一个表进行子查询时进行更新。@Cheekysoft,为什么不将值保存到变量中呢?@PeterV.Mørch如果执行某些操作,则无法进行合并。例如,为派生的虚拟表提供一个不合适的限制,这样就不会发生错误。这是一个相当骇人听闻的想法,而且MySQL的未来版本仍然存在支持合并查询和限制的风险。请您提供一个完整的例子来说明这个解决方法好吗?更新tbl SET col=选择。。。从选择。。。。从AS x开始;我仍然收到错误罪人加入我的工作:相关:似乎MySQL bug跟踪器中的功能请求在这里:这不能仅仅作为更新技能集type='Development'WHERE type='Programming'来编写吗?这似乎并没有回答最初的问题。似乎有些过分,@lilbyrdie是正确的-它只能是更新技能集type='Development',其中type='Programming';。我不明白为什么这么多人不考虑他们的所作所为……这是最好的答案,伊姆霍。它的语法很容易理解,您可以重复使用以前的语句,而且它不限于某些超级特定的情况。即使示例情况有问题,该原则也是最容易理解的,并在实际场景中部署。所显示的查询之所以有效,是因为表列表中的隐式联接为子查询创建了一个临时表,从而提供了稳定的结果,并避免了检索和修改同一个表之间的冲突。不管有人怎么说,这是一种过激行为,它仍然从标题方面回答了这个问题。OP提到的错误在尝试使用嵌套查询中的同一个表进行更新时也会遇到,这可能是因为我今天处于绑定状态,但这是最简单的答案,即使它可能不是最好的答案。这非常有效,谢谢!那么这里的逻辑是什么?如果它嵌套了一个以上的级别,那么它将在外部零件之前执行?如果它不是嵌套的,那么mySQL会在删除锁定表后尝试运行它?这个错误和解决方案没有逻辑意义…但它可以工作。有时我想知道MySQL开发者使用的是什么药物……同意@Cerin。。这完全是荒谬的,但它是有效的。@ekonoval感谢你提供的解决方案,但它对我来说毫无意义,看起来你在愚弄MySQL,他接受了它,lolAnd你刚刚丢失了所有外键,也许你也有一些级联删除。你能解释一下为什么这样有效,为什么只嵌套一个级别就有效吗?这个问题已经作为对@EkoNoval问题的评论被提出,但没有人回应。也许你能帮上忙。@AkshayArora,在@Cheekysoft的回答中,仔细阅读标题为“也许你可以自己加入表格”的部分。他说更新tbl作为内部连接tbl作为b ON。。。。SET a.col=b.col-这将作为此处使用的同一表的不同别名。类似地,在@NexusRex的答案中,第一个SELECT查询充当一个派生表,第二次使用story_类别。所以OP中提到的错误不应该发生在这里,对吗?结果显示:'1064-您的SQL语法有错误;查看与您的MariaDB服务器版本相对应的手册,了解使用“LEFT JOIN SELECT categories.id FROM categories cat ON story_category.id=cat”的正确语法。在第1行使用多表删除时,必须指定受影响的表。从中删除故事类别。。。但是,在c语言中不需要联接子查询
在cat.id=story\u category.category\u id中,如果cat.id为空,请注意答案中的连接条件错误地引用了story\u category.id=cat.id,这是上述所有答案的最容易理解和逻辑实现。简单明了。这已经成为我工作流程的一部分了。陷入这个错误,直接回答这个问题并纠正这个问题。谢谢,我现在就要用这个把戏了。奥瑟斯为这家公司工作,但他没有更多的选票。还应注意,多表语法也适用于UPDATE语句和联接子查询。允许您执行左连接选择。。。与“选择…”中的位置相反,使实现在许多用例中都有用。
-- set-up
create table story_category(category_id int);
create table category (id int);
insert into story_category values (1), (2), (3), (4), (5);
insert into category values (4), (5), (6), (7);

-- your original query to identify offending rows
SELECT * 
FROM  story_category 
WHERE category_id NOT IN (
    SELECT DISTINCT category.id 
    FROM category INNER JOIN 
       story_category ON category_id=category.id);
| category_id | | ----------: | | 1 | | 2 | | 3 |
-- a functionally-equivalent, simpler query for this
select sc.*
from story_category sc
where not exists (select 1 from category c where c.id = sc.category_id)
| category_id | | ----------: | | 1 | | 2 | | 3 |
-- the delete query
delete from story_category
where not exists (select 1 from category c where c.id = story_category.category_id);

-- outcome
select * from story_category;
| category_id | | ----------: | | 4 | | 5 |