UPDATE 語句html
UPDATE 是修改表中行的 DML 語句。mysql
UPDATE 語句能夠用 WITH 子句開頭,定義在 UPDATE 中可訪問的公共表表達式。sql
單表語法:安全
1. UPDATE [LOW_PRIORITY] [IGNORE] table_reference 2. SET assignment_list 3. [WHERE where_condition] 4. [ORDER BY ...] 5. [LIMIT row_count] 6. 7. value: 8. {expr | DEFAULT} 9. 10. assignment: 11. col_name = value 12. 13. assignment_list: 14. assignment [, assignment] ...
多表語法:ide
1. UPDATE [LOW_PRIORITY] [IGNORE] table_references 2. SET assignment_list 3. [WHERE where_condition]
對於單表語法,UPDATE 語句用新值更新命名錶中現有行的列。SET 子句指示要修改的列及其應給定的值。每一個值能夠用表達式給定,也可使用關鍵字 DEFAULT 將列顯式設置爲其默認值。WHERE 子句(若是給定)指定要更新哪些行。若是沒有 WHERE 子句,全部行都將更新。若是指定了 ORDER BY 子句,則按指定的順序更新行。LIMIT 子句對能夠更新的行數進行了限制。函數
對於多表語法,UPDATE 更新 table_references 中每一個表中知足條件的行。每一個匹配的行都會更新一次,即便它與條件匹配屢次。對於多表語法,不能使用 ORDER BY 和 LIMIT。優化
對於分區表,此語句的單表和多表形式都支持使用 PARTITION 選項用做表引用的一部分。此選項接受分區或子分區列表。只檢查列出的分區(或子分區)是否匹配,不在這些分區或子分區中的行不會更新,不管它是否知足 where_condition 條件。日誌
注意code
與在 INSERT 或 REPLACE 語句中使用 PARTITION 的狀況不一樣,即便列出的分區(或子分區)中沒有與 where_condition 匹配的行,UPDATE ... PARTITION 語句也被認爲是成功的。htm
where_condition 是一個表達式,要更新的每一行都必須知足此表達式的條件。
只須要擁有在 UPDATE 語句實際更新引用的列的 UPDATE 權限。對於任何已讀取但未修改的列,只須要 SELECT 權限。
UPDATE 語句支持如下修飾符:
● 使用 LOW_PRIORITY 修飾符,UPDATE 的執行將被延遲,直到沒有其餘客戶端從表中讀取數據。這隻影響只使用表級鎖定的存儲引擎(如 MyISAM、MEMORY 和 MERGE)。
● 使用 IGNORE 修飾符,即便在更新過程當中發生錯誤,更新語句也不會停止。不會更新在惟一鍵值上引起重複鍵衝突的行。可能致使數據轉換錯誤的值的行將更新爲最接近的有效值。
包括 ORDER BY 子句的 UPDATE IGNORE 語句被標記爲不安全的基於語句的複製。(這是由於行的更新順序決定了哪些行被忽略。)當使用基於語句的模式時,這些語句在錯誤日誌中生成警告,在使用 MIXED 模式時,這些語句將使用基於行的格式寫入二進制日誌。
若是從要在表達式中更新的表中訪問列,則 UPDATE 將使用該列的當前值。例如,下面的語句將 col1 設置爲比當前值多1:
1. UPDATE t1 SET col1 = col1 + 1;
下面語句中的第二個賦值將 col2 設置爲當前(更新的)col1 值,而不是原始 col1 值。結果是 col1 和 col2 的值相同。此行爲與標準 SQL 不一樣。
1. UPDATE t1 SET col1 = col1 + 1, col2 = col1;
單表 UPDATE 分配一般從左到右進行計算。對於多表更新,不能保證以任何特定的順序執行分配。
若是將列設置爲當前的值,MySQL 會注意到這一點,而且不會更新它。
若是把已聲明爲 NOT NULL 的列設置爲 NULL,則在啓用了嚴格 SQL 模式會出錯;不然,該列將設置爲列數據類型的隱式默認值,而且警告計數將遞增。對於數值類型,隱式默認值爲0;對於字符串類型,隱式默認值爲空字符串(''),對於日期和時間類型,默認值爲「零」。
若是顯式更新生成列,則惟一容許的值是 DEFAULT。
UPDATE 返回實際更改的行數。mysql_info() C API 函數返回匹配和更新的行數以及更新過程當中出現的警告數。
可使用 LIMIT row_count 來限制 UPDATE 的範圍。LIMIT 子句是匹配行的限制。只要找到知足 WHERE 子句的 row_count 行,語句就會當即中止,而無論這些行是否實際被更改。
若是 UPDATE 語句包含 ORDER BY 子句,則按該子句指定的順序更新行。這在某些可能致使錯誤的狀況下很是有用。假設表 t 包含一個具備惟一索引的列 id。如下語句可能會出現重複鍵錯誤而失敗,這取決於行的更新順序:
1. UPDATE t SET id = id + 1;
例如,若是表在 id 列中包含值 1 和 2,而且在 2 更新爲 3 以前 1 先更新爲2,則會發生錯誤。若要避免此問題,請添加 ORDER BY 子句,使 id 值較大的行在值較小的行以前更新:
1. UPDATE t SET id = id + 1 ORDER BY id DESC;
還能夠執行覆蓋多個表的 UPDATE 操做。可是,不能將 ORDER BY 或 LIMIT 用於多表更新。table_references 子句列出了鏈接中涉及的表。
1. UPDATE items,month SET items.price=month.price 2. WHERE items.id=month.id;
前面的示例顯示了使用逗號運算符的內部聯接,但多表更新語句可使用 SELECT 語句中容許的任何類型的聯接,例如 LEFT JOIN。
若是使用包含 InnoDB 表且有外鍵約束的多表 UPDATE 語句,那麼 MySQL 優化器可能會按照與父/子關係不一樣的順序處理表。在本例中,語句失敗並回滾。相反,更新一個表並依賴 InnoDB 提供的 ON UPDATE 功能來相應地修改其餘表。
不能在更新一個表的同時直接從子查詢中對同一表進行選擇。能夠經過使用多表更新來解決此問題,其中一個表是從實際要更新的表派生的,並使用別名引用派生表。假設但願更新一個名爲 items 的表,該表是使用如下語句定義的:
1. CREATE TABLE items ( 2. id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY, 3. wholesale DECIMAL(6,2) NOT NULL DEFAULT 0.00, 4. retail DECIMAL(6,2) NOT NULL DEFAULT 0.00, 5. quantity BIGINT NOT NULL DEFAULT 0 6. );
若要下降利潤爲30%或更高而且庫存少於100的商品的零售價,能夠嘗試使用以下所示的 UPDATE 語句,該語句在 WHERE 子句中使用子查詢。以下所示,此語句不起做用:
1. mysql> UPDATE items 2. > SET retail = retail * 0.9 3. > WHERE id IN 4. > (SELECT id FROM items 5. > WHERE retail / wholesale >= 1.3 AND quantity > 100); 6. ERROR 1093 (HY000): You can't specify target table 'items' for update in FROM clause
替代方法是可使用多表更新,其中子查詢被移動到要更新的表列表中,使用別名在最外層的 WHERE 子句中引用它,以下所示:
1. UPDATE items, 2. (SELECT id FROM items 3. WHERE id IN 4. (SELECT id FROM items 5. WHERE retail / wholesale >= 1.3 AND quantity < 100)) 6. AS discounted 7. SET items.retail = items.retail * 0.9 8. WHERE items.id = discounted.id;
由於默認狀況下,優化器會嘗試將派生表 discounted 合併到最外層的查詢塊中,只有在強制物化派生表時,這纔有效。能夠在運行更新以前將 optimizer_switch 系統變量的 derived_merge 標誌設置爲 off,或使用 NO_MERGE 優化器提示來執行此操做,以下所示:
1. UPDATE /*+ NO_MERGE(discounted) */ items, 2. (SELECT id FROM items 3. WHERE retail / wholesale >= 1.3 AND quantity < 100) 4. AS discounted 5. SET items.retail = items.retail * 0.9 6. WHERE items.id = discounted.id;
在這種狀況下使用優化器提示的好處是,它只適用於使用它的查詢塊中,所以在執行 UPDATE 以後,沒必要再次更改 optimizer_switch 的值。
另外一種多是重寫子查詢,使其不使用 IN 或 EXISTS,以下所示:
1. UPDATE items, 2. (SELECT id, retail / wholesale AS markup, quantity FROM items) 3. AS discounted 4. SET items.retail = items.retail * 0.9 5. WHERE discounted.markup >= 1.3 6. AND discounted.quantity < 100 7. AND items.id = discounted.id;
在這種狀況下,子查詢默認狀況下是物化的,而不是合併的,所以不須要禁用派生表的合併。