首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> MySQL 資料庫 >> MySQL 綜合教學

MySQL UPDATE 的 SET 子句順序陷阱:左至右評估 vs SQL Server 快照隔離

     編輯:MySQL 綜合教學

現象複現

CREATE TABLE test(id INT, tag INT, num INT);
INSERT INTO test VALUES (1,1,1), (2,2,2), (3,3,3);

-- 測試 1:tag 在前,num 在後
UPDATE test SET tag = 4, num = CASE WHEN tag = 4 THEN 4 ELSE 3 END WHERE tag = 3;
-- MySQL 結果:tag=4, num=4  (因 tag 已更新為 4,CASE 判斷為真)
-- SQL Server 結果:tag=4, num=3 (依據更新前快照,tag=3,CASE 判斷為假)

-- 測試 2:調換順序,num 在前,tag 在後
UPDATE test SET num = CASE WHEN tag = 4 THEN 4 ELSE 3 END, tag = 4 WHERE tag = 3;
-- MySQL 結果:tag=4, num=3  (num 計算時 tag 仍為 3)
-- SQL Server 結果:tag=4, num=3  (快照機制,順序無影響)

核心差異對照表

特性MySQL (InnoDB)SQL Server
SET 子句評估順序左至右,後欄位可見前欄位已更新值全欄位基於 更新前快照,順序無關
CASE/函式內引用同表欄位讀到「已更新」的值讀到「原始」的值
標準相容性不符合 SQL:2003 標準符合標準行為

避坑指南

  1. 不要在同一 UPDATE 中「先改欄位 A,再用 A 計算欄位 B」 —— MySQL 會產生非預期結果。
  2. 若需依「舊值」計算新值,請改用子查詢或暫存變數:
    UPDATE test t
    JOIN (SELECT id, CASE WHEN tag = 3 THEN 4 ELSE 3 END AS new_num FROM test WHERE tag = 3) src
      ON t.id = src.id
    SET t.tag = 4, t.num = src.new_num;
  3. 或分兩步執行:先 UPDATE ... SET num = ... WHERE tag = 3; 再 UPDATE ... SET tag = 4 WHERE tag = 3;。
  4. 程式碼審查時,特別檢查 SET a = ..., b = f(a) ... 這類模式。

延伸閱讀

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved