萬盛學電腦網

您现在的位置: 萬盛學電腦網 >> 程式設計 >  >> 資料庫 >> MySQL 教學

MySQL UPDATE 更新數據完整語法指南:單表、多表、條件、限制、返回值

UPDATE 是修改現有數據的核心 DML 語句。本文系統講解單表/多表更新語法、WHERE 條件最佳實踐、ORDER BY/LIMIT 控制、返回值判斷、事務配合、效能優化與常見陷阱。

基本語法


UPDATE [LOW_PRIORITY] [IGNORE] table_name
SET col1 = expr1, col2 = expr2, ...
[WHERE where_condition]
[ORDER BY ...]
[LIMIT row_count]

單表更新實戰範例

1. 更新所有行(慎用)


UPDATE links SET url = 'https://www.example.com';
-- 影響所有行,無 WHERE 保護

2. 條件更新(標準業務)


-- 修改指定用戶密碼
UPDATE users SET password_hash = SHA2('newpass', 256) WHERE username = 'admin';

-- 批量狀態變更
UPDATE orders SET status = 2, updated_at = NOW() WHERE status = 1 AND created_at < '2023-01-01';

3. 運算式更新(基於原值計算)


-- 庫存扣減
UPDATE products SET stock = stock - 1 WHERE id = 100 AND stock > 0;

-- 計數器增量
UPDATE stats SET pv = pv + 1 WHERE date = CURDATE() AND page = '/home';

-- 字串拼接
UPDATE users SET nickname = CONCAT(nickname, '_vip') WHERE level >= 10;

4. ORDER BY + LIMIT 控制更新範圍


-- 只更新前 100 條符合條件的記錄(按 id 升序)
UPDATE logs SET processed = 1 WHERE processed = 0 ORDER BY id ASC LIMIT 100;

-- 避免大事務長鎖,分批處理大量更新

多表更新(MySQL 專有語法)


-- 內連接更新:僅更新雙方匹配的行
UPDATE orders o
INNER JOIN users u ON o.user_id = u.id
SET o.user_name = u.username, o.user_email = u.email
WHERE o.user_name IS NULL;

-- 左連接更新:更新左表所有行,右表匹配則帶入值,否則 NULL
UPDATE products p
LEFT JOIN categories c ON p.category_id = c.id
SET p.category_name = COALESCE(c.name, '未分類');

返回值與影響行數判斷

語言/介面獲取影響行數說明
MySQL 客戶端Query OK, 3 rows affected直接顯示
PHP PDO$stmt->rowCount()返回影響行數
PHP mysqli$mysqli->affected_rows屬性
Java JDBCstmt.executeUpdate()返回 int
Python PyMySQLcursor.rowcount屬性
Go database/sqlresult.RowsAffected()返回 (int64, error)

事務與鎖控制


START TRANSACTION;

UPDATE accounts SET balance = balance - 100 WHERE id = 1 AND balance >= 100;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;

COMMIT;
-- 或 ROLLBACK;
  • 行鎖:InnoDB 對 WHERE 條件匹配的**索引記錄**加排他鎖(X 鎖)。
  • 間隙鎖/Next-Key Lock:RR 隔離級下,範圍條件會鎖定間隙防止幻讀。
  • 無索引 WHERE:全表掃描 → **鎖全表所有行**(極其危險)。**永遠確保 WHERE 條件走索引**。

效能優化清單

  1. WHERE 必須命中索引:EXPLAIN UPDATE ... (8.0+) 驗證 type=ref/range。
  2. 避免更新主鍵/唯一鍵欄位:引發 Delete+Insert、外鍵級聯、索引重建。
  3. 大批量更新分批:每批 500-1000 行,配合 LIMIT、id > last_id 游標,避免長事務、Replication 延遲、Undo Log 膨脹。
  4. 只更新變更的欄位:SET col = new_val 而非全欄位 SET col1=val1, col2=val2...,減少 Redo/Undo 體積。
  5. 使用 IGNORE 忽略重複鍵錯誤:UPDATE IGNORE t SET uk_col = 'x' ... 遇到唯一鍵衝突跳過該行不報錯。

常見陷阱

陷阱後果修正
忘記 WHERE全表更新,業務災難養成「先寫 SELECT 驗證 WHERE」習慣
WHERE 欄位無索引全表掃描 + 全表鎖定建立索引、或分批用主鍵範圍
子查詢更新同表ERROR 1093: You can't specify target table for update in FROM clause改用 JOIN 或多步驟
更新大字段 (TEXT/BLOB)產生大量 Undo/Redo、碎片拆表垂直分離、或對象存儲
隱式類型轉換索引失效、數據截斷參數綁定、CAST 顯式轉換

PHP 完整範例


 PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_EMULATE_PREPARES => false,
]);

try {
    $pdo->beginTransaction();
    
    $stmt = $pdo->prepare("UPDATE users SET balance = balance - ? WHERE id = ? AND balance >= ?");
    $affected = $stmt->execute([100.00, 123, 100.00]);
    
    if ($stmt->rowCount() === 0) {
        throw new Exception("Insufficient balance or user not found");
    }
    
    $pdo->commit();
    echo "Update success, rows: " . $stmt->rowCount();
} catch (Exception $e) {
    $pdo->rollBack();
    echo "Update failed: " . $e->getMessage();
}
?>
copyright © 萬盛學電腦網 all rights reserved