HOWTO · MySQL
在 MySQL 中使用一個查詢更新多個表
本文介紹如何在 MySQL 中一次查詢更新多個表。
本頁內容
當一項操作需要同時變更相關資料表中的資料列時,可以使用多資料表 UPDATE 陳述式。例如,借出書籍時,可以減少 library 中的可借冊數,同時增加 stu_book 中記錄為學生借閱的冊數。JOIN 條件會找出彼此相關的資料列,而同一個陳述式可以指定兩個資料表的變更內容。使用單一陳述式可以省去分別發送多個更新呼叫,但不會因此保證執行時間更短或業務資料一定正確;這些結果仍取決於結構描述、條件、索引、交易設定和應用程式需求。
在 MySQL 中使用一個查詢更新多張資料表的優點
在一個陳述式中更新相關資料列,有助於清楚表達它們之間的關係,也能降低應用程式只送出其中一項更新、漏掉另一項的風險。若兩項變更都在同一個陳述式中成功,資料庫會依據交易與儲存引擎的行為一併套用這些變更。若需要更強的應用程式層級保障,請使用適當的交易,並確認相關資料表的限制條件與錯誤處理方式。
如果應用程式原本會對同一個資料庫分別送出多個更新,這種寫法也能減少往返次數。但它不一定比較快:查詢計畫、索引、鎖定競爭、資料列數量和網路成本都會影響效能。如果速度很重要,請依照自己的工作負載比較這種寫法與分開執行的陳述式。它的主要好處是用一個 SQL 陳述式表達彼此協調的變更,而非保證在所有設定下都有更短的回應時間或一致性。
在 MySQL 中使用 UPDATE 關鍵字以一個查詢更新多張資料表
MySQL 的多資料表更新語法會在 UPDATE 後列出目標資料表,在 SET 中指定欄位值,並以 JOIN 條件選取相關資料列。UPDATE 和 SET 是兩個不同的關鍵字;「多資料表更新」描述的是這項操作,並不是合併成一個關鍵字。一般形式如下:UPDATE table1 AS a JOIN table2 AS b ON a.key = b.key SET a.column = value1, b.column = value2 WHERE condition;。JOIN 運算式會連結資料列,而 WHERE 可進一步限制要變更的符合資料。如果兩個資料表有同名欄位,請在欄位名稱前加上資料表別名,以明確指出欄位所屬。
以借出書籍為例,假設 library.id 是書籍識別碼,而 stu_book.book_id 參照該識別碼。下方的 Python 範例會在記憶體中模擬一本符合條件的書籍和一筆學生借閱記錄,用來說明兩個冊數如何成對變更;它不會連線到 MySQL,也不會執行 SQL。
執行此範例:
本節中的程式碼以及顯示的標籤或輸出仍為英文。
library = {"id": 7, "book_count": 5}
stu_book = {"book_id": 7, "book_count": 0}
if library["id"] == stu_book["book_id"]:
library["book_count"] -= 2
stu_book["book_count"] += 2
print(f'library={library["book_count"]}, stu_book={stu_book["book_count"]}')
對應的 SQL 陳述式如下:UPDATE library AS l JOIN stu_book AS s ON l.id = s.book_id SET l.book_count = l.book_count - 2, s.book_count = s.book_count + 2 WHERE l.id = 7;。它會從符合條件的 library 資料列扣除兩冊,並在符合條件的 stu_book 資料列增加兩冊。請依照資料模型調整數量與篩選條件;在實際的借書流程中,應先確認圖書館有足夠的館藏,且學生借閱記錄有效。本文中的 SQL 只是語法示例,並未對資料庫執行,因此沒有經 MySQL 驗證的輸出。
即使 JOIN 產生多筆符合結果,多資料表更新仍會讓每個符合條件的目標資料列只更新一次。請讓 JOIN 鍵與條件足夠明確,確保陳述式選取的是預期記錄。此處的關聯是 library.id = stu_book.book_id;範例並未使用 library_id 欄位,因此引用它並不正確。在對正式環境資料執行變更前,請先檢查 JOIN 和篩選條件。
與單一資料表更新不同,多資料表更新不能使用 ORDER BY 或 LIMIT。如果需要限制更新的資料列範圍,請先使用合適的條件或其他可確保交易安全的方式選出並識別該範圍,再於不使用這些子句的情況下更新。命令列用戶端顯示的「受影響資料列」訊息會依實際符合條件且有變更的資料,以及用戶端行為而異;它不能證明業務操作符合預期。如果正確性很重要,請確認相關資料列與應用程式的不變條件。