MySQL SELECT同时UPDATE同一张表 You can't specify target table 'sys_user' for update in FROM clause
2016-01-04 15:18
549 查看
SELECT uin,account,password,create_user_uin_tree FROM sys_user
结果:
表中的create_user_uin_tree标识该条记录由谁创建。
创建新用户时,根据当前登录用户的uin及新创建的用户uin,有如下SQL:
select concat(ifNULL(create_user_uin_tree,concat('_',2,'_')),'|_','97',"_") from sys_user where uin=2
结果:
那么修改的create_user_uin_tree的标识SQL为:
update sys_user set create_user_uin_tree=(select concat(ifNULL(temp.create_user_uin_tree,concat('_',2,'_')),'|_','97',"_") from sys_user temp where temp.uin=2) where uin = 97;
报错信息:
Error Code: 1093. You can't specify target table 'sys_user' for update in FROM clause 0.000 sec
原因:
mysql中不能这么用。 (等待mysql升级吧)。那串英文错误提示就是说,不能先select出同一表中的某些值,再update这个表(在同一语句中)。
两种方法:
1、select from 修改为子查询方式
2、inner join
方法1:子查询方式
调整了下SQL:
update sys_user set create_user_uin_tree=(select temp.tree from (select concat(ifNULL(create_user_uin_tree,concat('_',97,'_')),'|_','98',"_") as tree from sys_user where uin=97) temp) where uin = 98;
我将作为子集,
select concat(ifNULL(create_user_uin_tree,concat('_',97,'_')),'|_','98',"_") as tree from sys_user where uin=97) temp
然后再
select temp.tree from(子集)
子集,这样就不会 select 和 update 都是同一个表。致此问题得到完美解决。
方法2:inner join
在sql server中,我们可是使用以下update语句对表进行更新:
update a set a.xx= (select yy from b) where a.id = b.id ;
但是在mysql中,不能直接使用set select的结果,必须使用inner join:
update a inner join (select yy from b) c on a.id =b.id set a.xx = c.yy
MySQL不允许SELECT FROM后面指向用作UPDATE的表,有时候让人纠结。当然,有比创建无休止的临时表更好的办法。本文解释如何UPDATE一张表,同时在查询子句中使用SELECT.
假设我要UPDATE的表跟查询子句是同一张表,这样做有许多种原因,例如用统计数据更新表的字段(此时需要用group子句返回统计值),从某一条记录的字段update另一条记录,而不必使用非标准的语句,等等。举个例子:
错误提示是:ERROR 1093 (HY000): You can't specify target table 'apples' for update in FROM clause. MySQL手册UPDATE documentation这下面有说明 : “Currently, you cannot update a table and select from the same table in a subquery.”
在这个例子中,要解决问题也十分简单,但有时候不得不通过查询子句来update目标。好在我们有办法。
既然MySQL是通过临时表来实现FROM子句里面的嵌套查询,那么把嵌套查询装进另外一个嵌套查询里,可使FROM子句查询和保存都是在临时表里进行,然后间接地在外围查询被引用。下面的语句是正确的:
update apples set price = ( select price from ( select * from apples ) as x where variety = 'gala') where variety = 'fuji';
如果你想了解更多其中的机制,请阅读MySQL Internals Manual相关章节。
没有解决的问题
一个常见的问题是,IN()子句优化废品,被重写成相关的嵌套查询,有时(往往?)造成性能低下。把嵌套查询装进另外一个嵌套查询里并不能阻止它重写成相关嵌套,除非我下狠招。这种情况下,最好用JOIN重构查询(rewrite such a query as a join)。另一个没解决的问题是临时表被引用多次。“装进嵌套查询”的技巧无法解决这些问题,因为它们在编译时被创建,而上面讨论的update问题是在运行时。(译者注:个人认为跟文章讨论的主题没几毛钱关系)
相关文章推荐
- MySQL触发器更新本表数据异常:Can’t update table ‘tbl’ in stored function/trigger because it is already used by s
- 浅谈MySQL主键
- MYSQL获取自增ID的四种方法
- MySQL 序列使用AUTO_INCREMENT
- 解决win8及8.1安装mysql等msi类型文件2503,2502的问题
- mysql在dos界面修改密码
- concat() mysql 多个字段拼接
- 关于DOS界面net start MySQL 启动失败的解决办法
- MySql安装种种
- Mysql 里CHAR和VARCHAR的最大长度及一些注意事项
- 解决mysql max_allowed_packet 太小 造成的程序查询数据报错问题
- mysql中char(n)和varchar(n)在数据存入的时候关于是否丢弃最后的空格的区别
- mysql自带的字符串相关函数
- MySQL 5.7 zip安装
- 批量修改MySQL列级别字符排序方式为utf8
- mysql排序
- Mysql进程管理
- MySQL之——Union
- mysql explain用法
- [转]MySQL 5.7 新特性大全和未来展望