UPDATE 是修改現有資料的核心 DML 指令。內部實作為「刪除舊列 + 插入新列」,理解其機制有助於撰寫高效更新語句。
UPDATESET = [, ...] [WHERE ];
table_name:目標資料表 (可為檢視表、CTE、衍生表)。column_name = value:指派新值,可為常數、變數、子查詢、運算式。WHERE:**最關鍵子句**,限定更新範圍。省略則更新全表 (極危險)。UPDATE Users SET Phone = '78789831' WHERE UserId = 231;
-- 所有商品漲價 11% UPDATE Shop SET Price = Price * 1.11;
-- 依訂單狀態更新會員等級 UPDATE m SET m.Level = CASE WHEN o.Status = 'Completed' THEN 'VIP' ELSE 'Normal' END FROM Members m JOIN Orders o ON m.MemberId = o.MemberId WHERE o.OrderDate >= '2024-01-01';
UPDATE Products SET LastOrderDate = (SELECT MAX(OrderDate) FROM Orders WHERE Orders.ProductId = Products.ProductId) WHERE EXISTS (SELECT 1 FROM Orders WHERE Orders.ProductId = Products.ProductId);
| 原則 | 說明 |
|---|---|
| 永遠加 WHERE | 避免全表掃描與全表鎖定 |
| WHERE 欄位建索引 | 定位行數 < 10% 時用索引查找,否則掃描 |
| 避免函數包裹欄位 | WHERE YEAR(Date)=2024 → WHERE Date >= '2024-01-01' AND Date < '2025-01-01' |
| 批次更新大量資料 | 分批 (TOP 5000) 循環更新,避免長交易、記錄檔暴漲、鎖升級 |
| 減少更新列 | 僅更新實際變更的列,觸發器/CDC/複寫開銷最小化 |
| 注意觸發器 | AFTER UPDATE 觸發器會成倍增加執行時間 |
DECLARE @BatchSize INT = 5000, @RowCount INT = 1;
WHILE @RowCount > 0
BEGIN
UPDATE TOP (@BatchSize) LargeTable
SET Status = 2
WHERE Status = 1; -- 僅更新符合條件的行
SET @RowCount = @@ROWCOUNT;
-- 可選:WAITFOR DELAY '00:00:00.1' 降低壓力
END
WHERE VarcharCol = 123 導致索引失效,改用 '123'。SET Col = (SELECT ...) 若子查詢多列報錯,用 TOP 1 或聚合。LEFT JOIN 更新右表可能產生非預期結果,謹慎使用。