如果您指定 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 中移除。請改為使用資料列和欄位別名,如下一節所述。
可以在 VALUES
或 SET
子句之後使用資料列的別名,並選擇性地使用要插入的一個或多個欄位,並在前面加上 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;
此外,如果您使用欄位別名 m
、n
和 p
,則可以省略指派子句中的資料列別名,並將相同的陳述式寫成這樣
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)