文件首頁
MySQL 8.4 參考手冊
相關文件 下載本手冊
PDF (US Ltr) - 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 參考手冊  /  ...  /  REPLACE 陳述式

15.2.12 REPLACE 陳述式

REPLACE [LOW_PRIORITY | DELAYED]
    [INTO] tbl_name
    [PARTITION (partition_name [, partition_name] ...)]
    [(col_name [, col_name] ...)]
    { {VALUES | VALUE} (value_list) [, (value_list)] ...
      |
      VALUES row_constructor_list
    }

REPLACE [LOW_PRIORITY | DELAYED]
    [INTO] tbl_name
    [PARTITION (partition_name [, partition_name] ...)]
    SET assignment_list

REPLACE [LOW_PRIORITY | DELAYED]
    [INTO] tbl_name
    [PARTITION (partition_name [, partition_name] ...)]
    [(col_name [, col_name] ...)]
    {SELECT ... | TABLE table_name}

value:
    {expr | DEFAULT}

value_list:
    value [, value] ...

row_constructor_list:
    ROW(value_list)[, ROW(value_list)][, ...]

assignment:
    col_name = value

assignment_list:
    assignment [, assignment] ...

REPLACE 的運作方式與 INSERT 完全相同,差別在於如果資料表中舊的資料列,其 PRIMARY KEYUNIQUE 索引的值與新的資料列相同,則會在插入新的資料列之前刪除舊的資料列。請參閱第 15.2.7 節「INSERT 陳述式」

REPLACE 是 MySQL 對 SQL 標準的擴充。它會插入,或刪除並插入。如需另一個 MySQL 對標準 SQL 的擴充(插入或更新),請參閱第 15.2.7.2 節「INSERT ... ON DUPLICATE KEY UPDATE 陳述式」

DELAYED 插入和取代在 MySQL 5.6 中已棄用。在 MySQL 8.4 中,不支援 DELAYED。伺服器會辨識但忽略 DELAYED 關鍵字,將取代處理為非延遲取代,並產生 ER_WARN_LEGACY_SYNTAX_CONVERTED 警告:不再支援 REPLACE DELAYED。該陳述式已轉換為 REPLACEDELAYED 關鍵字預計在未來版本中移除。

注意

只有當資料表具有 PRIMARY KEYUNIQUE 索引時,REPLACE 才有意義。否則,它會等同於 INSERT,因為沒有索引可用來判斷新的資料列是否與其他資料列重複。

所有資料行的值都取自 REPLACE 陳述式中指定的值。任何遺失的資料行都會設定為其預設值,就像 INSERT 一樣。您無法參照目前資料列中的值並在新的資料列中使用它們。如果您使用類似 SET col_name = col_name + 1 的指派,則右手邊對資料行名稱的參照會被視為 DEFAULT(col_name),因此該指派等同於 SET col_name = DEFAULT(col_name) + 1

您可以使用 VALUES ROW() 指定 REPLACE 嘗試插入的資料行值。

若要使用 REPLACE,您必須擁有資料表的 INSERTDELETE 權限。

如果明確取代產生的資料行,則唯一允許的值是 DEFAULT。如需有關產生的資料行的資訊,請參閱第 15.1.20.8 節「CREATE TABLE 和產生的資料行」

REPLACE 支援使用 PARTITION 子句明確選取分割區,其中包含以逗號分隔的分割區、子分割區或兩者名稱清單。與 INSERT 一樣,如果無法將新的資料列插入任何這些分割區或子分割區,則 REPLACE 陳述式會失敗並出現錯誤 找到與給定分割區集不符的資料列。如需更多資訊和範例,請參閱第 26.5 節「分割區選取」

REPLACE 陳述式會傳回一個計數,以表示受影響的資料列數。這是刪除和插入的資料列總和。如果單一資料列的 REPLACE 計數為 1,則表示已插入資料列且未刪除任何資料列。如果計數大於 1,則表示在插入新的資料列之前刪除了一或多個舊的資料列。如果資料表包含多個唯一索引,且新的資料列在不同的唯一索引中複製不同舊資料列的值,則單一資料列可能會取代多個舊資料列。

受影響的資料列計數可以讓您輕鬆判斷 REPLACE 是否僅新增資料列或是否也取代了任何資料列:檢查計數是否為 1(已新增)或大於 1(已取代)。

如果您使用的是 C API,則可以使用 mysql_affected_rows() 函數取得受影響的資料列計數。

您無法在子查詢中取代到資料表,並從同一個資料表選取。

MySQL 使用下列演算法來處理 REPLACE (和 LOAD DATA ... REPLACE)

  1. 嘗試將新的資料列插入資料表

  2. 當因為主要索引鍵或唯一索引發生重複索引鍵錯誤而導致插入失敗時

    1. 從資料表中刪除具有重複索引鍵值的衝突資料列

    2. 再次嘗試將新的資料列插入資料表

在發生重複索引鍵錯誤時,儲存引擎可能會執行 REPLACE 作為更新,而不是刪除加上插入,但語意相同。除了儲存引擎如何遞增 Handler_xxx 狀態變數之外,沒有其他使用者可見的影響。

由於 REPLACE ... SELECT 陳述式的結果取決於來自 SELECT 的資料列排序,且此順序並非總是能保證,因此在記錄這些陳述式時,來源和複本可能會分歧。因此,REPLACE ... SELECT 陳述式會被標示為對於以陳述式為基礎的複寫不安全。當使用以陳述式為基礎的模式時,此類陳述式會在錯誤記錄中產生警告,且在使用 MIXED 模式時會使用以資料列為基礎的格式寫入二進位記錄。另請參閱第 19.2.1.1 節「以陳述式為基礎和以資料列為基礎的複寫的優點和缺點」

MySQL 8.4 支援 TABLE 以及 SELECTREPLACE,就像它對 INSERT 一樣。如需更多資訊和範例,請參閱第 15.2.7.1 節「INSERT ... SELECT 陳述式」

當修改未分割的現有資料表以容納分割時,或當修改已分割資料表的分割時,您可能會考慮變更資料表的主要索引鍵 (請參閱第 26.6.1 節「分割區索引鍵、主要索引鍵和唯一索引鍵」)。您應該注意,如果您這樣做,REPLACE 陳述式的結果可能會受到影響,就像您修改非分割資料表的主要索引鍵一樣。請考慮由下列 CREATE TABLE 陳述式建立的資料表

CREATE TABLE test (
  id INT UNSIGNED NOT NULL AUTO_INCREMENT,
  data VARCHAR(64) DEFAULT NULL,
  ts TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (id)
);

當我們建立這個資料表並執行 mysql 用戶端中顯示的陳述式時,結果如下

mysql> REPLACE INTO test VALUES (1, 'Old', '2014-08-20 18:47:00');
Query OK, 1 row affected (0.04 sec)

mysql> REPLACE INTO test VALUES (1, 'New', '2014-08-20 18:47:42');
Query OK, 2 rows affected (0.04 sec)

mysql> SELECT * FROM test;
+----+------+---------------------+
| id | data | ts                  |
+----+------+---------------------+
|  1 | New  | 2014-08-20 18:47:42 |
+----+------+---------------------+
1 row in set (0.00 sec)

現在我們建立第二個幾乎與第一個資料表相同的資料表,但主要索引鍵現在涵蓋 2 個資料行,如下所示(強調文字)

CREATE TABLE test2 (
  id INT UNSIGNED NOT NULL AUTO_INCREMENT,
  data VARCHAR(64) DEFAULT NULL,
  ts TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (id, ts)
);

當我們在 test2 上執行與原始 test 資料表相同的兩個 REPLACE 陳述式時,我們會獲得不同的結果

mysql> REPLACE INTO test2 VALUES (1, 'Old', '2014-08-20 18:47:00');
Query OK, 1 row affected (0.05 sec)

mysql> REPLACE INTO test2 VALUES (1, 'New', '2014-08-20 18:47:42');
Query OK, 1 row affected (0.06 sec)

mysql> SELECT * FROM test2;
+----+------+---------------------+
| id | data | ts                  |
+----+------+---------------------+
|  1 | Old  | 2014-08-20 18:47:00 |
|  1 | New  | 2014-08-20 18:47:42 |
+----+------+---------------------+
2 rows in set (0.00 sec)

這是因為在 test2 上執行時,idts 資料行值都必須與現有資料列的值相符,才能取代該資料列;否則,會插入資料列。