MySQL的SQL語句 - 數據操做語句(15)- UPDATE 語句

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;

在這種狀況下,子查詢默認狀況下是物化的,而不是合併的,所以不須要禁用派生表的合併。

官方網址:
https://dev.mysql.com/doc/refman/8.0/en/update.html

相關文章
相關標籤/搜索