mysql update不支持子查詢更新


 
        

先看示例:

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中不支持子查詢更新,准確的說是更新的表不能在set和where中用於子查詢。那串英文錯誤提示就是說,不能先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子句查詢和保存都是在臨時表里進行,然后間接地在外圍查詢被引用。下面的語句是正確的:

CREATE TABLE `user2` (
  `id` INT(11) NOT NULL,
  `name` VARCHAR(50) DEFAULT NULL,
  `device` VARCHAR(40) DEFAULT NULL,
  `memo` VARCHAR(40) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;

INSERT  INTO `user2`(`id`,`name`,`device`,`memo`) VALUES (1,'duan','11',NULL),(2,'liang','12',NULL),(3,'hou','13',NULL);

//子查詢
UPDATE user2 SET memo=(SELECT temp.dc FROM (SELECT device AS dc FROM user2 WHERE id=2) temp) WHERE id = 2;
//列=列
UPDATE user2 SET memo=device;
//join

如果你想了解更多其中的機制,請閱讀MySQL Internals Manual相關章節。

沒有解決的問題

一個常見的問題是,IN()子句優化廢品,被重寫成相關的嵌套查詢,有時(往往?)造成性能低下。把嵌套查詢裝進另外一個嵌套查詢里並不能阻止它重寫成相關嵌套,除非我下狠招。這種情況下,最好用JOIN重構查詢(rewrite such a query as a join)。

另一個沒解決的問題是臨時表被引用多次。“裝進嵌套查詢”的技巧無法解決這些問題,因為它們在編譯時被創建,而上面討論的update問題是在運行時。

 

另外一個示例:交換兩條記錄中的字段值方法

表test:  

    id         priority  

    1             1  

    2             2  

方法一:

mysql語句如下:

update question set sort=(case when id=7 then (select a.sort from (select tmp.* from question tmp) a
where a.id=8) when id=8  then (select a.sort from (select tmp.* from question tmp) a where a.id=7) end)
where id=7 or id=8; 

方法二:

update question as q1 join question as q2 on (q1.id=7 and q2.id = 8)
or(q1.id = 8 and q2.id=7)
set q1.sort = q2.sort,q2.sort=q1.sort;

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM