MySQL #1093 - 您不能在 FROM 子句中指定目标表“赠品”进行更新
Posted
技术标签:
【中文标题】MySQL #1093 - 您不能在 FROM 子句中指定目标表“赠品”进行更新【英文标题】:MySQL #1093 - You can't specify target table 'giveaways' for update in FROM clause 【发布时间】:2012-01-10 03:03:45 【问题描述】:我试过了:
UPDATE giveaways SET winner = '1' WHERE ID = (SELECT MAX(ID) FROM giveaways)
但它给出了:
#1093 - 您不能在
FROM
子句中指定要更新的目标表“赠品”
This article 似乎相关,但我无法使其适应我的查询。我怎样才能让它工作?
【问题讨论】:
您正在执行递归查询。你到底想做什么? giveaways表的记录很少。我想将赠品(具有最大 ID)的获胜者列设置为 1 @Gigi,很明显他想做什么。UPDATE giveaways SET winner = '1' WHERE ID = (SELECT MAX(ID) FROM giveaways)
【参考方案1】:
根据您链接到的文章中的信息应该可以:
update giveaways set winner='1'
where Id = (select Id from (select max(Id) as id from giveaways) as t)
【讨论】:
谢谢它的工作!但是你能解释一下,我应该选择哪种方式来表现?你的?还是@nick rulez (***.com/a/8333417/556169)? @Eray 这个答案和上面的 nick rulez' 答案是等价的,但是它们都使用了这里不需要的嵌套子查询。 @Eray。我认为我的查询不会比 ipr101 慢,因为即使我使用 *,查询也只检索一个标量值。所以我没有得到任何不必要的价值。顺便说一句,我赞成马修的回答,因为它是更聪明的解决方案,我不明白为什么有人反对它。 @Pacerier 将其保存到变量中然后使用该变量将不再是巧合编码,而是会引入竞争条件。 @Pacerier 你不会,你会得到一个竞争条件。如果您不想要竞争条件,则需要一个表锁。这本质上不是死锁。【参考方案2】:这是因为您的更新可能是周期性的......如果更新该记录导致发生WHERE
条件FALSE
的事情怎么办?你知道情况并非如此,但引擎不会。操作中也可能存在桌子上的对立锁。
我认为你可以这样做(未经测试):
UPDATE
giveaways
SET
winner = '1'
ORDER BY
id DESC
LIMIT 1
Read more
【讨论】:
已经过测试和批准。耗时 0.0002 秒。 @Matthew,关于 “如果更新该记录会导致发生WHERE
条件FALSE
的事情怎么办?”,因为where
子句已经评估,为什么这很重要?为什么 mysql 不够聪明,无法自动执行此操作(ipr101 和 nick 的回答)?
@Pacerier 原因是这些解决方案对嵌套子查询使用隐式查询。当您告诉引擎从嵌套子查询中选择内容时,您隐含地强制它首先执行该语句。如果不这样做(如所写),查询计划器将尝试优化嵌套。这是巧合的编码,这意味着您依赖于查询计划器的特定行为并且是不好的做法。
@Matthew,那么,真正的问题不是与“查询规划器将尝试优化嵌套”有关吗?在像update t where id=(select max(id)from t)
这样的查询中,很明显查询规划器不应该尝试优化嵌套,因为可以看出(select max(id)from t)
是应该首先运行的内部查询。
@Pacerier 否。查询计划器的默认行为通常不首先执行嵌套子查询,因为它们可能能够更有效地组合到 out 查询中。这两个答案利用了这个明确的SELECT
,迫使查询计划者的行为。这当然有效,但对计划者不利。这是巧合的编码。您无法控制查询计划器的行为方式,并且您不应编写代码以利用其巧合行为。【参考方案3】:
update giveaways set winner=1
where Id = (select*from (select max(Id)from giveaways)as t)
【讨论】:
谢谢它的工作!但是你能解释一下,我应该选择哪种方式来表现?你的?还是 @ipr101 的 (***.com/a/8333445/556169)? 我的查询和ipr101的查询是一样的。他们只是使用临时表解决方法来避免您报告的错误。顺便说一句,马修的解决方案也很好。 ;)【参考方案4】:create table GIVEAWAYS_NEW as(select*from giveaways);
update giveaways set winner=1
where Id=(select max(Id)from GIVEAWAYS_NEW);
【讨论】:
复制整个表格,性能会不会很糟糕? 它还有并发问题:由于您使用多个语句,您可能需要将其包装在事务中,否则赠品中的最大 Id 可能会在create table
和 update
之间变化.【参考方案5】:
利用TEMP TABLE:
如下:
UPDATE TABLE_NAME SET TABLE_NAME.IsActive=TRUE
WHERE TABLE_NAME.Id IN (
SELECT Id
FROM TEMPDATA
);
CREATE TEMPORARY TABLE TEMPDATA
SELECT MAX(TABLE_NAME.Id) as Id
FROM TABLE_NAME
GROUP BY TABLE_NAME.IncidentId;
SELECT * FROM TEMPDATA;
DROP TABLE TEMPDATA;
【讨论】:
【参考方案6】:您可以先创建子查询的视图,然后从视图中更新/删除选择。 请记住在之后删除视图。
【讨论】:
以上是关于MySQL #1093 - 您不能在 FROM 子句中指定目标表“赠品”进行更新的主要内容,如果未能解决你的问题,请参考以下文章
#1093 - 您不能在 FROM 子句中指定目标表 'comments' 进行更新
#1093 - 您不能在 FROM 子句中指定目标表 'tbl' 进行更新 [重复]
#1093 - 您不能在 FROM 子句中指定要更新的目标表 [重复]