Mysql SELECT 里面的 UPDATE

Posted

技术标签:

【中文标题】Mysql SELECT 里面的 UPDATE【英文标题】:Mysql SELECT inside UPDATE 【发布时间】:2010-12-29 16:25:47 【问题描述】:
UPDATE forms SET

pos = (SELECT MIN(pos)-1 FROM forms)

WHERE id=$id

这不起作用,错误消息:

**You can't specify target table 'form' for update in FROM clause**

我希望很清楚:我想从同一张表中获取最小的 element-1 并将其分配给 pos

【问题讨论】:

【参考方案1】:

你的问题is stated plainly in the mysql manual:

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

您需要使用事务。关闭 AutoCommit,开始事务,然后执行 SELECT MIN(pos)-1 FROM forms FOR UPDATE,获取结果,使用它进行更新,然后提交事务。

【讨论】:

【参考方案2】:

Consp 是正确的,它不受支持。但是,有一个解决方法:

UPDATE forms SET
pos = (SELECT MIN(pos)-1 FROM (SELECT * FROM forms) AS x)
WHERE id=$id

可能更快的版本:

UPDATE forms 
SET pos = (SELECT pos-1 FROM (SELECT MIN(pos) AS pos FROM forms) AS x)
where id=$id

【讨论】:

+1 表示“限制你的任意异想天开的限制”。希望它可以工作,我自己不再使用mysql了。 ...大家不要忘记使用 isnull() 以防表为空 我试图让它更快一点,但我还没有测量性能。您可能需要试一试,看看哪种方法最适合您的数据。 这不是一个任意的异想天开的限制......这是因为 SELECT 应该导致锁定相关行,但是这些行已经被 UPDATE 语句锁定,并且没有人编写逻辑来正确执行锁定而不会导致语句本身可能死锁。 -- 请注意,通过创建您要选择的临时表,此 UPDATE 语句实际上并不是原子的,并且可能会执行多个具有相同 pos 的 UPDATE。 这样的请求创建了一个无休止的进程,我的服务器变得不可用。这可能是由于我在请求中包含的附加功能,但要小心。 transactions 为我工作,没有任何问题。【参考方案3】:

你也可以试试:

START TRANSACTION;
SET @newMin := MIN(pos)-1 FROM forms;
UPDATE forms SET pos=@newMin WHERE id='$id';
COMMIT;

【讨论】:

对于 MariaDB,第二行应该以 SELECT 而不是 SET 开头:mariadb.com/kb/en/start-transaction/#examples【参考方案4】:

我认为您不能在更新语句中使用子查询,但无论如何都有解决方法...

这是来自以下网站的报价:

"dev.mysql.com"

“目前,您不能从一个表中删除并在子查询中从同一个表中选择”

【讨论】:

以上是关于Mysql SELECT 里面的 UPDATE的主要内容,如果未能解决你的问题,请参考以下文章

mysql里面 limit的奇效

mysql 里面的isnull()和ifnull() is null 和 is not null

MySQL里面的子查询

MySQL里面的子查询实例

存储过程里面set赋值怎么没有起到作用

mysql in 排序 也可以按in里面的顺序来排序