文件首頁
MySQL 8.4 參考手冊
相關文件 下載本手冊
PDF (美式信紙) - 39.9Mb
PDF (A4) - 40.0Mb
Man Pages (TGZ) - 258.5Kb
Man Pages (Zip) - 365.5Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb


MySQL 8.4 參考手冊  /  ...  /  INSERT ... ON DUPLICATE KEY UPDATE 陳述式

15.2.7.2 INSERT ... ON DUPLICATE KEY UPDATE 陳述式

如果您指定 ON DUPLICATE KEY UPDATE 子句,並且要插入的資料列會在 UNIQUE 索引或 PRIMARY KEY 中造成重複的值,則會對舊資料列執行 UPDATE。例如,如果欄位 a 宣告為 UNIQUE 並且包含值 1,則以下兩個陳述式具有類似的效果

INSERT INTO t1 (a,b,c) VALUES (1,2,3)
  ON DUPLICATE KEY UPDATE c=c+1;

UPDATE t1 SET c=c+1 WHERE a=1;

效果並非完全相同:對於 InnoDB 資料表,其中 a 是自動遞增欄位,INSERT 陳述式會增加自動遞增值,但 UPDATE 不會。

如果欄位 b 也是唯一的,則 INSERT 等同於此 UPDATE 陳述式

UPDATE t1 SET c=c+1 WHERE a=1 OR b=2 LIMIT 1;

如果 a=1 OR b=2 符合多個資料列,則只會更新 一個 資料列。一般來說,您應盡量避免在具有多個唯一索引的資料表上使用 ON DUPLICATE KEY UPDATE 子句。

使用 ON DUPLICATE KEY UPDATE,如果資料列作為新資料列插入,則每個資料列的受影響資料列值為 1;如果更新現有資料列,則為 2;如果現有資料列設定為其目前值,則為 0。如果您在連線至 mysqld 時,將 CLIENT_FOUND_ROWS 旗標指定給 mysql_real_connect() C API 函式,則如果現有資料列設定為其目前值,則受影響資料列值為 1 (而不是 0)。

如果資料表包含 AUTO_INCREMENT 欄位,且 INSERT ... ON DUPLICATE KEY UPDATE 插入或更新資料列,則 LAST_INSERT_ID() 函式會傳回 AUTO_INCREMENT 值。

ON DUPLICATE KEY UPDATE 子句可以包含多個以逗號分隔的欄位指派。

ON DUPLICATE KEY UPDATE 子句中的指派值運算式中,您可以使用 VALUES(col_name) 函式來參照來自 INSERT 部分的欄位值 INSERT ... ON DUPLICATE KEY UPDATE 陳述式。換句話說,ON DUPLICATE KEY UPDATE 子句中的 VALUES(col_name) 參照將要插入的 col_name 的值,如果沒有發生重複鍵衝突。此函式在多列插入中特別有用。VALUES() 函式僅在 ON DUPLICATE KEY UPDATE 子句或 INSERT 陳述式中才有意義,否則會傳回 NULL。範例

INSERT INTO t1 (a,b,c) VALUES (1,2,3),(4,5,6)
  ON DUPLICATE KEY UPDATE c=VALUES(a)+VALUES(b);

該陳述式與以下兩個陳述式相同

INSERT INTO t1 (a,b,c) VALUES (1,2,3)
  ON DUPLICATE KEY UPDATE c=3;
INSERT INTO t1 (a,b,c) VALUES (4,5,6)
  ON DUPLICATE KEY UPDATE c=9;
請注意

使用 VALUES() 來參照新資料列和欄位已過時,並且可能會在未來版本的 MySQL 中移除。請改為使用資料列和欄位別名,如下一節所述。

可以在 VALUESSET 子句之後使用資料列的別名,並選擇性地使用要插入的一個或多個欄位,並在前面加上 AS 關鍵字。使用資料列別名 new,先前顯示使用 VALUES() 存取新欄位值的陳述式可以寫成此處顯示的形式

INSERT INTO t1 (a,b,c) VALUES (1,2,3),(4,5,6) AS new
  ON DUPLICATE KEY UPDATE c = new.a+new.b;

此外,如果您使用欄位別名 mnp,則可以省略指派子句中的資料列別名,並將相同的陳述式寫成這樣

INSERT INTO t1 (a,b,c) VALUES (1,2,3),(4,5,6) AS new(m,n,p)
  ON DUPLICATE KEY UPDATE c = m+n;

以這種方式使用欄位別名時,您仍然必須在 VALUES 子句之後使用資料列別名,即使您沒有在指派子句中直接使用它。

UPDATE 子句中使用 VALUES()INSERT ... SELECT ... ON DUPLICATE KEY UPDATE 陳述式 (如此處的陳述式) 會擲回警告

INSERT INTO t1
  SELECT c, c+d FROM t2
  ON DUPLICATE KEY UPDATE b = VALUES(b);

您可以使用子查詢來消除此類警告,如下所示

INSERT INTO t1
  SELECT * FROM (SELECT c, c+d AS e FROM t2) AS dt
  ON DUPLICATE KEY UPDATE b = e;

您也可以如先前所述,將資料列和欄位別名與 SET 子句一起使用。將 SET 用於取代先前顯示的兩個 INSERT ... ON DUPLICATE KEY UPDATE 陳述式中的 VALUES,可以如下所示進行

INSERT INTO t1 SET a=1,b=2,c=3 AS new
  ON DUPLICATE KEY UPDATE c = new.a+new.b;

INSERT INTO t1 SET a=1,b=2,c=3 AS new(m,n,p)
  ON DUPLICATE KEY UPDATE c = m+n;

資料列別名不得與資料表的名稱相同。如果未使用欄位別名,或者它們與欄位名稱相同,則必須在 ON DUPLICATE KEY UPDATE 子句中使用資料列別名來區分它們。相對於它們所套用的資料列別名,欄位別名必須是唯一的(也就是說,沒有參照相同資料列的欄位別名可以相同)。

對於 INSERT ... SELECT 陳述式,下列規則適用於您可以在 ON DUPLICATE KEY UPDATE 子句中參照的可接受 SELECT 查詢運算式形式

  • 從單一資料表 (可以是衍生資料表) 的查詢中參照欄位。

  • 從多個資料表上聯結的查詢中參照欄位。

  • DISTINCT 查詢中參照欄位。

  • 參照其他資料表中的欄位,只要 SELECT 沒有使用 GROUP BY。其中一個副作用是您必須限定參照非唯一的欄位名稱。

不支援從 UNION 中參照欄位。若要解決此限制,請將 UNION 重寫為衍生資料表,使其資料列可以視為單一資料表的結果集。例如,此陳述式會產生錯誤

INSERT INTO t1 (a, b)
  SELECT c, d FROM t2
  UNION
  SELECT e, f FROM t3
ON DUPLICATE KEY UPDATE b = b + c;

請改用將 UNION 重寫為衍生資料表的等效陳述式

INSERT INTO t1 (a, b)
SELECT * FROM
  (SELECT c, d FROM t2
   UNION
   SELECT e, f FROM t3) AS dt
ON DUPLICATE KEY UPDATE b = b + c;

將查詢重寫為衍生資料表的技術也可用於參照來自 GROUP BY 查詢的欄位。

由於 INSERT ... SELECT 陳述式的結果取決於 SELECT 的資料列順序,且無法保證此順序,因此當記錄來源和複本的 INSERT ... SELECT ON DUPLICATE KEY UPDATE 陳述式時,可能會發生差異。因此,INSERT ... SELECT ON DUPLICATE KEY UPDATE 陳述式會被標記為對於以陳述式為基礎的複寫而言是不安全的。使用以陳述式為基礎的模式時,此類陳述式會在錯誤記錄檔中產生警告,並且在使用 MIXED 模式時,會使用以資料列為基礎的格式寫入二進位記錄檔。針對具有多個唯一索引或主鍵的資料表執行的 INSERT ... ON DUPLICATE KEY UPDATE 陳述式也會被標記為不安全。(錯誤 #11765650, 錯誤 #58637)

另請參閱章節 19.2.1.1,「以陳述式為基礎與以資料列為基礎的複寫的優缺點」