MySQL SELECT同時UPDATE同一張表

MySQL不容許SELECT FROM後面指向用做UPDATE的表,有時候讓人糾結。固然,有比建立無休止的臨時表更好的辦法。本文解釋如何UPDATE一張表,同時在查詢子句中使用SELECT.

問題描述

假設我要UPDATE的表跟查詢子句是同一張表,這樣作有許多種緣由,例如用統計數據更新表的字段(此時須要用group子句返回統計值),從某一條記錄的字段update另外一條記錄,而沒必要使用非標準的語句,等等。舉個例子:
[sql]  view plain copy
  1. create table apples(variety char(10) primary key, price int);  
  2.   
  3. insert into apples values('fuji', 5), ('gala', 6);  
  4.   
  5. update apples  
  6.     set price = (select price from apples where variety = 'gala')  
  7.     where variety = 'fuji';  

錯誤提示是: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子句查詢和保存都是在臨時表裏進行,而後間接地在外圍查詢被引用。下面的語句是正確的:
[sql]  view plain copy
  1. update apples  
  2.    set price = (  
  3.       select price from (  
  4.          select * from apples  
  5.       ) as x  
  6.       where variety = 'gala')  
  7.    where variety = 'fuji';  

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

沒有解決的問題

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

另外一個沒解決的問題是臨時表被引用屢次。「裝進嵌套查詢」的技巧沒法解決這些問題,由於它們在編譯時被建立,而上面討論的update問題是在運行時。(譯者注:我的認爲跟文章討論的主題沒幾毛錢關係)


原文地址 http://www.xaprb.com/blog/2006/06/23/how-to-select-from-an-update-target-in-mysql/
相關文章
相關標籤/搜索