表 product(id, name, original_price, price) 需將「原價」與「現價」兩列數值互換。
UPDATE product SET original_price = price, price = original_price;
執行流程:
original_price = price → 原價列覆蓋為現價值price = original_price → 此時 original_price 已是新值,相當於 price = price,**現價列不變**結果:兩列均變為原現價值,**原價數據永久丟失**。
UPDATE product AS a
INNER JOIN product AS b ON a.id = b.id
SET a.original_price = b.price,
a.price = b.original_price;
原理:將同一表作為兩個別名 a、b 參與連接,SET 子句同時讀取 b 的舊值寫入 a,互不干擾。等效於「快照讀取 → 批量寫入」。
| 方案 | SQL | 優點 | 缺點 |
|---|---|---|---|
| 自連接 UPDATE | UPDATE t a JOIN t b ON a.id=b.id SET a.x=b.y, a.y=b.x | 單條語句、原子性、無臨時對象 | 大表鎖表時間長 |
| 臨時變量 | UPDATE t SET x=@tmp:=x, x=y, y=@tmp | 無自連接開銷 | 依賴變量求值順序,版本間行為可能不一致,不推薦 |
| 中間表 | CREATE TEMP TABLE tmp AS SELECT id, y AS new_x, x AS new_y FROM t; UPDATE t JOIN tmp ... | 大表分批提交、可中斷恢復 | 需額外存儲、多步驟 |
| 應用層讀改寫 | SELECT → 交換 → 批量 UPDATE | 業務邏輯可控、易測試 | 網絡往返、併發衝突風險 |
若需 a→b, b→c, c→a 三列循環:
UPDATE t AS a
JOIN t AS b ON a.id = b.id
SET a.col1 = b.col2,
a.col2 = b.col3,
a.col3 = b.col1;
MySQL UPDATE 多列賦值**按書寫順序依次執行**,直接互換會導致數據覆蓋。**自連接 UPDATE** 是標準、安全、單語句解法:UPDATE t a JOIN t b ON a.pk=b.pk SET a.col1=b.col2, a.col2=b.col1。大表操作建議分批次(按主鍵範圍)執行,或維護窗口期執行,避免長事務阻塞業務。